secure_gate/error.rs
1//! Centralized error types for the secure-gate crate.
2//!
3//! Errors are designed with security in mind: debug builds include detailed context
4//! (e.g., expected vs. actual lengths, HRP values) to aid development and testing,
5//! while release builds use generic messages to avoid leaking sensitive information
6//! about decoding failures or secret properties.
7//!
8//! All decoding-related errors follow this hardening pattern.
9//! (Zeroization is handled at the wrapper level — see `Fixed`/`Dynamic` docs.)
10
11use thiserror::Error;
12
13/// Error returned when a byte slice cannot be converted to a fixed-size array.
14///
15/// In **debug builds** includes expected and actual lengths for development debugging.
16/// In **release builds** uses generic messages to prevent leaking expected-length metadata.
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)]
18pub enum FromSliceError {
19 #[cfg(debug_assertions)]
20 /// Length mismatch in debug builds (detailed).
21 #[error("slice length mismatch: expected {expected}, got {actual}")]
22 InvalidLength {
23 /// Actual slice length in bytes.
24 actual: usize,
25 /// Expected length in bytes.
26 expected: usize,
27 },
28 #[cfg(not(debug_assertions))]
29 /// Length mismatch in release builds (generic).
30 #[error("slice length mismatch")]
31 InvalidLength,
32}
33
34/// Errors produced when decoding Bech32 (BIP-173) or Bech32m (BIP-350) strings.
35///
36/// *Requires feature `encoding-bech32` or `encoding-bech32m`.*
37///
38/// In **debug builds** `UnexpectedHrp` and `InvalidLength` carry `expected`/`got`
39/// fields for development debugging. In **release builds** these variants are opaque
40/// to prevent leaking expected-length or HRP metadata.
41#[cfg(any(feature = "encoding-bech32", feature = "encoding-bech32m"))]
42#[derive(Clone, Debug, PartialEq, Eq, Error)]
43pub enum Bech32Error {
44 /// The Human-Readable Part (HRP) is invalid.
45 #[error("invalid Human-Readable Part (HRP)")]
46 InvalidHrp,
47 /// Bit conversion during encoding/decoding failed.
48 ///
49 /// **Currently unreachable.** After `CheckedHrpstring::new()` succeeds, the
50 /// `.byte_iter()` iterator is infallible — all bit-conversion happens during
51 /// the `new()` call and any failure surfaces as `OperationFailed` instead.
52 /// This variant is preserved as public API for forward compatibility should a
53 /// fallible conversion path be introduced in a future release of the `bech32` crate.
54 #[error("bit conversion failed")]
55 ConversionFailed,
56 /// General bech32 operation failure.
57 #[error("bech32 operation failed")]
58 OperationFailed,
59 #[cfg(debug_assertions)]
60 /// Unexpected HRP in debug builds (detailed).
61 #[error("unexpected HRP: expected {expected}, got {got}")]
62 UnexpectedHrp {
63 /// Human-readable part that was expected.
64 expected: String,
65 /// Human-readable part present in the input.
66 got: String,
67 },
68 #[cfg(not(debug_assertions))]
69 /// Unexpected HRP in release builds (generic).
70 #[error("unexpected HRP")]
71 UnexpectedHrp,
72 #[cfg(debug_assertions)]
73 /// Length mismatch in debug builds (detailed).
74 #[error("decoded length mismatch: expected {expected}, got {got}")]
75 InvalidLength {
76 /// Expected decoded length in bytes.
77 expected: usize,
78 /// Actual decoded length in bytes.
79 got: usize,
80 },
81 #[cfg(not(debug_assertions))]
82 /// Length mismatch in release builds (generic).
83 #[error("decoded length mismatch")]
84 InvalidLength,
85}
86
87/// Errors produced when decoding base64url strings.
88///
89/// *Requires feature `encoding-base64`.*
90///
91/// In **debug builds** `InvalidLength` carries `expected`/`got` fields for
92/// development debugging. In **release builds** this variant is opaque to
93/// prevent leaking expected-length metadata.
94#[cfg(feature = "encoding-base64")]
95#[derive(Clone, Debug, PartialEq, Eq, Error)]
96pub enum Base64Error {
97 /// The string is not valid base64url.
98 #[error("invalid base64 string")]
99 InvalidBase64,
100 #[cfg(debug_assertions)]
101 /// Length mismatch in debug builds (detailed).
102 #[error("decoded length mismatch: expected {expected}, got {got}")]
103 InvalidLength {
104 /// Expected decoded length in bytes.
105 expected: usize,
106 /// Actual decoded length in bytes.
107 got: usize,
108 },
109 #[cfg(not(debug_assertions))]
110 /// Length mismatch in release builds (generic).
111 #[error("decoded length mismatch")]
112 InvalidLength,
113}
114
115/// Errors produced when decoding hexadecimal strings.
116///
117/// *Requires feature `encoding-hex`.*
118///
119/// In **debug builds** `InvalidLength` carries `expected`/`got` fields for
120/// development debugging. In **release builds** this variant is opaque to
121/// prevent leaking expected-length metadata.
122#[cfg(feature = "encoding-hex")]
123#[derive(Clone, Debug, PartialEq, Eq, Error)]
124pub enum HexError {
125 /// The string is not valid hexadecimal.
126 #[error("invalid hex string")]
127 InvalidHex,
128 #[cfg(debug_assertions)]
129 /// Length mismatch in debug builds (detailed).
130 #[error("decoded length mismatch: expected {expected}, got {got}")]
131 InvalidLength {
132 /// Expected decoded length in bytes.
133 expected: usize,
134 /// Actual decoded length in bytes.
135 got: usize,
136 },
137 #[cfg(not(debug_assertions))]
138 /// Length mismatch in release builds (generic).
139 #[error("decoded length mismatch")]
140 InvalidLength,
141}
142
143/// Unified error type for multi-format decoding operations.
144///
145/// Wraps format-specific errors from hex, base64url, bech32, and bech32m decoders.
146/// Always available; variants depend on enabled features.
147#[derive(Clone, Debug, Error)]
148pub enum DecodingError {
149 /// Bech32 or Bech32m decoding failed.
150 #[cfg(feature = "encoding-bech32")]
151 #[error("invalid bech32 string")]
152 InvalidBech32(#[source] Bech32Error),
153 /// Base64url decoding failed.
154 #[cfg(feature = "encoding-base64")]
155 #[error("invalid base64 string")]
156 InvalidBase64(#[source] Base64Error),
157 /// Hexadecimal decoding failed.
158 #[cfg(feature = "encoding-hex")]
159 #[error("invalid hex string")]
160 InvalidHex(#[source] HexError),
161 /// Generic encoding failure in debug builds (includes a non-sensitive hint).
162 #[cfg(debug_assertions)]
163 #[error("invalid encoding: {hint}")]
164 InvalidEncoding {
165 /// Short hint for developers (debug builds only).
166 hint: String,
167 },
168 #[cfg(not(debug_assertions))]
169 /// Generic encoding failure in release builds (opaque).
170 #[error("invalid encoding")]
171 InvalidEncoding,
172}