wolf_crypto/
error.rs

1use core::fmt;
2use core::convert::Infallible;
3
4/// A generic error type representing an unspecified failure in cryptographic operations.
5///
6/// In cryptographic contexts, it is often necessary to hide the specific reason for
7/// an operation's failure to prevent leaking sensitive information to potential attackers.
8/// `Unspecified` serves this purpose by providing a simple, non-descriptive error type
9/// that can be used in situations where the cause of the failure should not be exposed.
10#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Unspecified;
12
13impl fmt::Display for Unspecified {
14    /// Writes "Unspecified" to the formatter.
15    #[inline]
16    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17        f.write_str("Unspecified")
18    }
19}
20
21std! { impl std::error::Error for Unspecified {} }
22no_std_io! {
23    impl embedded_io::Error for Unspecified {
24        fn kind(&self) -> embedded_io::ErrorKind {
25            embedded_io::ErrorKind::Other
26        }
27    }
28}
29
30impl From<crate::buf::InvalidSize> for Unspecified {
31    #[inline]
32    fn from(_value: crate::buf::InvalidSize) -> Self { Self }
33}
34
35impl From<Infallible> for Unspecified {
36    #[inline]
37    fn from(_value: Infallible) -> Self { Self }
38}
39
40/// A key derivation function was attempted to be used with zero iterations.
41#[derive(Debug, Copy, Clone)]
42pub struct InvalidIters;
43
44impl fmt::Display for InvalidIters {
45    #[inline]
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        f.write_str("InvalidIters")
48    }
49}
50
51std! {
52    impl std::error::Error for InvalidIters {}
53}
54
55impl From<InvalidIters> for Unspecified {
56    #[inline]
57    fn from(_value: InvalidIters) -> Self { Self }
58}
59
60/// Trait for transforming a `Result<T, E>` into a `Result<T, Unspecified>`.
61///
62/// This trait is useful in contexts where you want to prevent specific error details from being
63/// exposed, such as in cryptographic operations or security-critical code paths, where leaking
64/// error information could aid in side-channel attacks.
65///
66/// # Examples
67///
68/// ```
69/// use wolf_crypto::{Unspecified, MakeOpaque};
70///
71/// let success: Result<u32, &str> = Ok(42);
72/// let result = success.opaque();
73/// assert_eq!(result, Ok(42));
74///
75/// let failure: Result<u32, &str> = Err("error");
76/// let result = failure.opaque();
77/// assert_eq!(result, Err(Unspecified));
78/// ```
79///
80/// **Bind Combinator**
81/// ```
82/// use wolf_crypto::{Unspecified, MakeOpaque};
83///
84/// let failure = Ok::<usize, ()>(7)
85///     .opaque_bind(|not_seven| if not_seven == 7 {
86///         Err("Did not expect 7")
87///     } else {
88///         Ok(not_seven)
89///     });
90/// assert_eq!(failure, Err(Unspecified));
91///
92/// let ok = Ok::<usize, ()>(42)
93///     .opaque_bind(|res| if res == 42 {
94///         Ok("meaning of life")
95///     } else {
96///         Err("Expected the meaning of life")
97///     });
98/// assert_eq!(ok, Ok("meaning of life"));
99/// ```
100///
101/// **Map Combinator**
102/// ```
103/// use wolf_crypto::{Unspecified, MakeOpaque};
104///
105/// assert_eq!(
106///     Err::<usize, usize>(7).opaque_map(|num| num * 6),
107///     Err(Unspecified)
108/// );
109/// assert_eq!(
110///     Ok::<usize, usize>(7).opaque_map(|num| num * 6),
111///     Ok(42)
112/// );
113/// ```
114#[allow(clippy::missing_errors_doc)]
115pub trait MakeOpaque<T> {
116    /// Transforms the `Result<T, E>` into a `Result<T, Unspecified>`.
117    ///
118    /// If the original `Result` was `Ok(T)`, it remains unchanged. However, if it was `Err(E)`,
119    /// the error is transformed into a generic `Unspecified` error, hiding the underlying cause.
120    ///
121    /// # Example
122    ///
123    /// ```
124    /// # use wolf_crypto::{MakeOpaque, Unspecified};
125    /// let success: Result<u32, &str> = Ok(42);
126    /// let result = success.opaque();
127    /// assert_eq!(result, Ok(42));
128    ///
129    /// let failure: Result<u32, &str> = Err("error");
130    /// let result = failure.opaque();
131    /// assert_eq!(result, Err(Unspecified));
132    /// ```
133    fn opaque(self) -> Result<T, Unspecified>;
134
135    /// Calls `op` if the result is [`Ok`], converting all errors to the [`Unspecified`] type.
136    ///
137    /// This method is similar to Rust's [`and_then`] and Haskell's `bind`, though it does not
138    /// require the closure to have the same error type due to it transforming all errors to the
139    /// [`Unspecified`] type.
140    ///
141    /// This function can be used for control flow based on `Result` values.
142    ///
143    /// # Example
144    ///
145    /// ```
146    /// # use wolf_crypto::{MakeOpaque, Unspecified};
147    /// let success: Result<u32, &str> = Ok(7);
148    /// let result = success.opaque_bind(|v| v.checked_mul(6).ok_or(()));
149    /// assert_eq!(result, Ok(42));
150    ///
151    /// let failure: Result<u32, &str> = Err("error");
152    /// let result = failure.opaque_bind(|v| v.checked_mul(6).ok_or(()));
153    /// assert_eq!(result, Err(Unspecified));
154    /// ```
155    ///
156    /// [`and_then`]: Result::and_then
157    fn opaque_bind<F: FnOnce(T) -> Result<N, NE>, N, NE>(self, op: F) -> Result<N, Unspecified>;
158
159    /// Maps a `Result<T, E>` to `Result<U, Unspecified>` by applying a function to a
160    /// contained [`Ok`] value, and replacing the error with [`Unspecified`].
161    ///
162    /// This function can be used to compose the results of two functions.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// # use wolf_crypto::{MakeOpaque, Unspecified};
168    /// let success: Result<u32, &str> = Ok(42);
169    /// let result = success.opaque_map(|v| v + 1);
170    /// assert_eq!(result, Ok(43));
171    ///
172    /// let failure: Result<u32, &str> = Err("error");
173    /// let result = failure.opaque_map(|v| v + 1);
174    /// assert_eq!(result, Err(Unspecified));
175    /// ```
176    fn opaque_map<F: FnOnce(T) -> N, N>(self, op: F) -> Result<N, Unspecified>;
177}
178
179#[allow(clippy::option_if_let_else)]
180impl<T, E> MakeOpaque<T> for Result<T, E> {
181    #[inline]
182    fn opaque(self) -> Result<T, Unspecified> {
183        match self {
184            Ok(ok) => Ok(ok),
185            Err(_) => Err(Unspecified)
186        }
187    }
188
189    #[inline]
190    fn opaque_bind<F: FnOnce(T) -> Result<N, NE>, N, NE>(self, op: F) -> Result<N, Unspecified> {
191        match self {
192            Ok(ok) => op(ok).opaque(),
193            Err(_) => Err(Unspecified)
194        }
195    }
196
197    #[inline]
198    fn opaque_map<F: FnOnce(T) -> N, N>(self, op: F) -> Result<N, Unspecified> {
199        match self {
200            Ok(ok) => Ok(op(ok)),
201            Err(_) => Err(Unspecified)
202        }
203    }
204}