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 { actual: usize, expected: usize },
23    #[cfg(not(debug_assertions))]
24    /// Length mismatch in release builds (generic).
25    #[error("slice length mismatch")]
26    InvalidLength,
27}
28
29/// Errors produced when decoding Bech32 (BIP-173) or Bech32m (BIP-350) strings.
30///
31/// *Requires feature `encoding-bech32` or `encoding-bech32m`.*
32///
33/// In **debug builds** `UnexpectedHrp` and `InvalidLength` carry `expected`/`got`
34/// fields for development debugging. In **release builds** these variants are opaque
35/// to prevent leaking expected-length or HRP metadata.
36#[cfg(any(feature = "encoding-bech32", feature = "encoding-bech32m"))]
37#[derive(Clone, Debug, PartialEq, Eq, Error)]
38pub enum Bech32Error {
39    /// The Human-Readable Part (HRP) is invalid.
40    #[error("invalid Human-Readable Part (HRP)")]
41    InvalidHrp,
42    /// Bit conversion during encoding/decoding failed.
43    ///
44    /// **Currently unreachable.** After `CheckedHrpstring::new()` succeeds, the
45    /// `.byte_iter()` iterator is infallible — all bit-conversion happens during
46    /// the `new()` call and any failure surfaces as `OperationFailed` instead.
47    /// This variant is preserved as public API for forward compatibility should a
48    /// fallible conversion path be introduced in a future release of the `bech32` crate.
49    #[error("bit conversion failed")]
50    ConversionFailed,
51    /// General bech32 operation failure.
52    #[error("bech32 operation failed")]
53    OperationFailed,
54    #[cfg(debug_assertions)]
55    /// Unexpected HRP in debug builds (detailed).
56    #[error("unexpected HRP: expected {expected}, got {got}")]
57    UnexpectedHrp { expected: String, got: String },
58    #[cfg(not(debug_assertions))]
59    /// Unexpected HRP in release builds (generic).
60    #[error("unexpected HRP")]
61    UnexpectedHrp,
62    #[cfg(debug_assertions)]
63    /// Length mismatch in debug builds (detailed).
64    #[error("decoded length mismatch: expected {expected}, got {got}")]
65    InvalidLength { expected: usize, got: usize },
66    #[cfg(not(debug_assertions))]
67    /// Length mismatch in release builds (generic).
68    #[error("decoded length mismatch")]
69    InvalidLength,
70}
71
72/// Errors produced when decoding base64url strings.
73///
74/// *Requires feature `encoding-base64`.*
75///
76/// In **debug builds** `InvalidLength` carries `expected`/`got` fields for
77/// development debugging. In **release builds** this variant is opaque to
78/// prevent leaking expected-length metadata.
79#[cfg(feature = "encoding-base64")]
80#[derive(Clone, Debug, PartialEq, Eq, Error)]
81pub enum Base64Error {
82    /// The string is not valid base64url.
83    #[error("invalid base64 string")]
84    InvalidBase64,
85    #[cfg(debug_assertions)]
86    /// Length mismatch in debug builds (detailed).
87    #[error("decoded length mismatch: expected {expected}, got {got}")]
88    InvalidLength { expected: usize, got: usize },
89    #[cfg(not(debug_assertions))]
90    /// Length mismatch in release builds (generic).
91    #[error("decoded length mismatch")]
92    InvalidLength,
93}
94
95/// Errors produced when decoding hexadecimal strings.
96///
97/// *Requires feature `encoding-hex`.*
98///
99/// In **debug builds** `InvalidLength` carries `expected`/`got` fields for
100/// development debugging. In **release builds** this variant is opaque to
101/// prevent leaking expected-length metadata.
102#[cfg(feature = "encoding-hex")]
103#[derive(Clone, Debug, PartialEq, Eq, Error)]
104pub enum HexError {
105    /// The string is not valid hexadecimal.
106    #[error("invalid hex string")]
107    InvalidHex,
108    #[cfg(debug_assertions)]
109    /// Length mismatch in debug builds (detailed).
110    #[error("decoded length mismatch: expected {expected}, got {got}")]
111    InvalidLength { expected: usize, got: usize },
112    #[cfg(not(debug_assertions))]
113    /// Length mismatch in release builds (generic).
114    #[error("decoded length mismatch")]
115    InvalidLength,
116}
117
118/// Unified error type for multi-format decoding operations.
119///
120/// Wraps format-specific errors from hex, base64url, bech32, and bech32m decoders.
121/// Always available; variants depend on enabled features.
122#[derive(Clone, Debug, Error)]
123pub enum DecodingError {
124    #[cfg(feature = "encoding-bech32")]
125    #[error("invalid bech32 string")]
126    InvalidBech32(#[source] Bech32Error),
127    #[cfg(feature = "encoding-base64")]
128    #[error("invalid base64 string")]
129    InvalidBase64(#[source] Base64Error),
130    #[cfg(feature = "encoding-hex")]
131    #[error("invalid hex string")]
132    InvalidHex(#[source] HexError),
133    #[cfg(debug_assertions)]
134    #[error("invalid encoding: {hint}")]
135    InvalidEncoding { hint: String },
136    #[cfg(not(debug_assertions))]
137    #[error("invalid encoding")]
138    InvalidEncoding,
139}