Skip to main content

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        /// Number of bytes actually provided.
24        actual: usize,
25        /// Number of bytes the target array requires.
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        /// The HRP the caller required.
64        expected: String,
65        /// The HRP found in the input string.
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        /// Number of bytes the target type requires.
77        expected: usize,
78        /// Number of bytes actually decoded.
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        /// Number of bytes the target type requires.
105        expected: usize,
106        /// Number of bytes actually decoded.
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        /// Number of bytes the target type requires.
133        expected: usize,
134        /// Number of bytes actually decoded.
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    /// The input is not valid Bech32.
150    #[cfg(feature = "encoding-bech32")]
151    #[error("invalid bech32 string")]
152    InvalidBech32(#[source] Bech32Error),
153    /// The input is not valid Base64url.
154    #[cfg(feature = "encoding-base64")]
155    #[error("invalid base64 string")]
156    InvalidBase64(#[source] Base64Error),
157    /// The input is not valid hexadecimal.
158    #[cfg(feature = "encoding-hex")]
159    #[error("invalid hex string")]
160    InvalidHex(#[source] HexError),
161    /// Encoding could not be identified (debug builds include a human-readable hint).
162    #[cfg(debug_assertions)]
163    #[error("invalid encoding: {hint}")]
164    InvalidEncoding {
165        /// Free-form description of the failure (debug builds only).
166        hint: String,
167    },
168    /// Encoding could not be identified (release builds omit details).
169    #[cfg(not(debug_assertions))]
170    #[error("invalid encoding")]
171    InvalidEncoding,
172}