sosecrets_rs/
traits.rs

1use crate::{
2    macros::{impl_choose_int, impl_sealed_trait_for_uint},
3    types::NumericalZeroSizedType,
4};
5use core::{
6    cmp::PartialOrd,
7    fmt::{Debug, Display},
8    hash::Hash,
9    ops::{Add, AddAssign},
10};
11use typenum::{IsLessOrEqual, Sum, True, Unsigned, U0, U1};
12
13/// A trait for safely exposing secrets with a limited exposure count.
14///
15/// The `ExposeSecret` trait provides a mechanism to progressively expose a secret
16/// value in a controlled manner, with an invariant lifetime and compile-time guarantees.
17/// It allows for limiting the exposure of a secret to a maximum count (`MEC`).
18/// The exposure count (`EC`) is tracked at compile time to ensure that it does not exceed the specified maximum count.
19///
20/// # Type Parameters
21/// - `'max`: A lifetime parameter indicating the lifetime of the value of the type that implements this trait.
22/// - `T`: The type of the secret being exposed.
23/// - `MEC`: A type-level unsigned integer (with `typenum::Unsigned` trait bound) representing the maximum exposure count.
24/// - `EC`: A type-level unsigned integer (with `typenum::Unsigned` trait bound) representing the current exposure count.
25pub trait ExposeSecret<'max, T, MEC: Unsigned, EC: Unsigned>: Sized {
26    /// A wrapper type representing the exposed secret. It is associated with a lifetime `'brand`, indicating the lifetime of the wrapper type, which is strictly a subtype of `'max`,
27    type Exposed<'brand>
28    where
29        'max: 'brand;
30
31    /// The `Secret<T, _, _>` with an incremented count (i.e. `EC`) after exposing the secret.
32    /// It is a new value of a type which implements the same trait, namely, `ExposeSecret` with an incremented exposure count, i.e. the new `EC` = previous `EC` + `1`.
33    type Next: ExposeSecret<'max, T, MEC, Sum<EC, U1>>
34    where
35        EC: Add<U1> + Unsigned + IsLessOrEqual<MEC, Output = True>,
36        Sum<EC, U1>: Unsigned + IsLessOrEqual<MEC, Output = True> + Add<U1>;
37
38    /// Exposes the secret and returns the `Secret<T, _, _>` with an incremented count (i.e. `EC`), along with the result of a provided closure.
39    /// It is impossible to return `Self::Exposed` associated type out from the closure `scope`.
40    ///
41    /// # Parameters
42    /// - `self`.
43    /// - `scope`: A closure (of the type given by the type parameter `ClosureType`) that takes the exposed secret, of type `Exposed<'brand>` and returns a result, of type `ReturnType`.
44    ///
45    /// Returns `(Self::Next, ReturnType)`
46    fn expose_secret<ReturnType, ClosureType>(self, scope: ClosureType) -> (Self::Next, ReturnType)
47    where
48        for<'brand> ClosureType: FnOnce(Self::Exposed<'brand>) -> ReturnType,
49        EC: Add<U1> + IsLessOrEqual<MEC, Output = True>,
50        Sum<EC, U1>: Unsigned + Add<U1> + IsLessOrEqual<MEC, Output = True>;
51}
52
53#[cfg(feature = "cloneable-secret")]
54pub use self::cloneable_secret::CloneableSecret;
55
56#[cfg(feature = "debug-secret")]
57pub use self::debug_secret::DebugSecret;
58
59#[cfg(feature = "cloneable-secret")]
60mod cloneable_secret {
61    //! Traits and implementations related to cloneable secrets.
62
63    use core::clone::Clone;
64
65    #[cfg(feature = "zeroize")]
66    use zeroize::Zeroize;
67
68    /// A trait for cloneable secrets.
69    ///
70    /// This trait extends the standard `Clone` trait for types that represent secrets,
71    /// allowing them to be cloned.
72    #[cfg(feature = "zeroize")]
73    pub trait CloneableSecret: Clone + Zeroize {}
74
75    /// A trait for cloneable secrets.
76    ///
77    /// This trait extends the standard `Clone` trait for types that represent secrets,
78    /// allowing them to be cloned.
79    #[cfg(not(feature = "zeroize"))]
80    pub trait CloneableSecret: Clone {}
81
82    impl<
83            #[cfg(feature = "zeroize")] T: Clone + Zeroize,
84            #[cfg(not(feature = "zeroize"))] T: Clone,
85            const N: usize,
86        > CloneableSecret for [T; N]
87    {
88    }
89
90    #[cfg(feature = "alloc")]
91    use alloc::{string::String, vec::Vec};
92
93    #[cfg(feature = "alloc")]
94    impl CloneableSecret for String {}
95
96    #[cfg(feature = "alloc")]
97    impl<
98            #[cfg(feature = "zeroize")] T: Clone + Zeroize,
99            #[cfg(not(feature = "zeroize"))] T: Clone,
100        > CloneableSecret for Vec<T>
101    {
102    }
103
104    crate::macros::impl_cloneable_secret_for_numbers!(
105        i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
106    );
107}
108
109#[cfg(feature = "debug-secret")]
110mod debug_secret {
111    use core::fmt::Debug;
112
113    #[cfg(feature = "zeroize")]
114    use zeroize::Zeroize;
115
116    /// A trait for debuggable secrets.
117    ///
118    /// This trait extends the standard `Debug` trait for types that represent secrets,
119    /// allowing them to be formatted for debugging purposes.
120    #[cfg(feature = "zeroize")]
121    pub trait DebugSecret: Debug + Zeroize {
122        /// Formats the secret as "`[REDACTED]`".
123        fn debug_secret(f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
124            f.write_str("[REDACTED]")
125        }
126    }
127
128    /// A trait for debuggable secrets.
129    ///
130    /// This trait extends the standard `Debug` trait for types that represent secrets,
131    /// allowing them to be formatted for debugging purposes.
132    #[cfg(not(feature = "zeroize"))]
133    pub trait DebugSecret: Debug {
134        /// Formats the secret as "`[REDACTED]`".
135        fn debug_secret(f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
136            f.write_str("[REDACTED]")
137        }
138    }
139
140    impl<
141            #[cfg(feature = "zeroize")] T: Debug + Zeroize,
142            #[cfg(not(feature = "zeroize"))] T: Debug,
143            const N: usize,
144        > DebugSecret for [T; N]
145    {
146    }
147
148    #[cfg(feature = "alloc")]
149    use alloc::{string::String, vec::Vec};
150
151    #[cfg(feature = "alloc")]
152    impl DebugSecret for String {}
153
154    #[cfg(feature = "alloc")]
155    impl<
156            #[cfg(feature = "zeroize")] T: Debug + Zeroize,
157            #[cfg(not(feature = "zeroize"))] T: Debug,
158        > DebugSecret for Vec<T>
159    {
160    }
161
162    crate::macros::impl_debug_secret_for_numbers!(
163        i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
164    );
165}
166
167impl_sealed_trait_for_uint!(u8, u16, u32, u64, u128);
168
169/// A trait for types that can choose the minimally representable unsigned integer.
170pub trait ChooseMinimallyRepresentableUInt: __private::SealedTrait {
171    /// The Rust's primitive unsigned integer type that is minimally representable of the unsigned integer represented at the type level by `Self`.
172    /// e.g. If `Self` is `typenum::consts::U69`, then `Self::Output` is `u8`.
173    type Output: AddAssign
174        + Add<Self::Output, Output = Self::Output>
175        + PartialOrd
176        + Debug
177        + Display
178        + Copy
179        + Eq
180        + Ord
181        + PartialOrd
182        + Clone
183        + Hash
184        + Default;
185    /// Currently, a placeholder for future feature of this crate. Safe to put a placeholder here because this is a 'Sealed' trait.
186    type AtomicOutput;
187    /// The additive identity of the type `Self::Output`, e.g. `0_usize`, `0_u32`.
188    const ZERO: Self::Output;
189    /// The multiplicative identity of the type `Self::Output`, e.g. `1_usize`, `1_u32`.
190    const ONE: Self::Output;
191
192    /// A convenient method to convert the unsigned integer represented at the type level by `Self` to a value of type `Self::Output`.
193    /// e.g. converting from `typenum::consts::U69` to `69_u8`.
194    fn cast_unsigned_to_self_type<T: Unsigned>(_: __private::SealedToken) -> Self::Output;
195}
196
197/// A trait for types that can be converted to their atomic representation.
198/// Currently, a placeholder for future feature of this crate. Safe to put a placeholder here because this is a 'Sealed' trait.
199pub trait AsAtomic: __private::SealedTrait {
200    type Output;
201}
202
203pub(crate) mod __private {
204
205    pub struct SealedToken {}
206    pub trait SealedTrait {}
207}
208
209#[cfg(target_pointer_width = "32")]
210impl_choose_int! {
211    B00 => u8;
212    B01 => u8;
213    B02 => u8;
214    B03 => u8;
215    B04 => u8;
216    B05 => u8;
217    B06 => u8;
218    B07 => u8;
219
220    B10 => u16;
221    B11 => u16;
222    B12 => u16;
223    B13 => u16;
224    B14 => u16;
225    B15 => u16;
226    B16 => u16;
227    B17 => u16;
228
229    B20 => u32;
230    B21 => u32;
231    B22 => u32;
232    B23 => u32;
233    B24 => u32;
234    B25 => u32;
235    B26 => u32;
236    B27 => u32;
237
238    B30 => u32;
239    B31 => u32;
240    B32 => u32;
241    B33 => u32;
242    B34 => u32;
243    B35 => u32;
244    B36 => u32;
245    B37 => u32;
246}
247
248#[cfg(target_pointer_width = "64")]
249impl_choose_int! {
250    B00 => u8;
251    B01 => u8;
252    B02 => u8;
253    B03 => u8;
254    B04 => u8;
255    B05 => u8;
256    B06 => u8;
257    B07 => u8;
258
259    B10 => u16;
260    B11 => u16;
261    B12 => u16;
262    B13 => u16;
263    B14 => u16;
264    B15 => u16;
265    B16 => u16;
266    B17 => u16;
267
268    B20 => u32;
269    B21 => u32;
270    B22 => u32;
271    B23 => u32;
272    B24 => u32;
273    B25 => u32;
274    B26 => u32;
275    B27 => u32;
276
277    B30 => u32;
278    B31 => u32;
279    B32 => u32;
280    B33 => u32;
281    B34 => u32;
282    B35 => u32;
283    B36 => u32;
284    B37 => u32;
285
286    B40 => u64;
287    B41 => u64;
288    B42 => u64;
289    B43 => u64;
290    B44 => u64;
291    B45 => u64;
292    B46 => u64;
293    B47 => u64;
294
295    B50 => u64;
296    B51 => u64;
297    B52 => u64;
298    B53 => u64;
299    B54 => u64;
300    B55 => u64;
301    B56 => u64;
302    B57 => u64;
303
304    B60 => u64;
305    B61 => u64;
306    B62 => u64;
307    B63 => u64;
308    B64 => u64;
309    B65 => u64;
310    B66 => u64;
311    B67 => u64;
312
313    B70 => u64;
314    B71 => u64;
315    B72 => u64;
316    B73 => u64;
317    B74 => u64;
318    B75 => u64;
319    B76 => u64;
320    B77 => u64;
321}
322
323impl __private::SealedTrait for U0 {}
324
325impl ChooseMinimallyRepresentableUInt for U0 {
326    type Output = NumericalZeroSizedType;
327    type AtomicOutput = NumericalZeroSizedType;
328
329    const ZERO: Self::Output = NumericalZeroSizedType {};
330    const ONE: Self::Output = NumericalZeroSizedType {};
331
332    fn cast_unsigned_to_self_type<T: Unsigned>(_: __private::SealedToken) -> Self::Output {
333        NumericalZeroSizedType {}
334    }
335}
336
337#[cfg(target_has_atomic = "8")]
338impl AsAtomic for u8 {
339    type Output = core::sync::atomic::AtomicU8;
340}
341
342#[cfg(target_has_atomic = "16")]
343impl AsAtomic for u16 {
344    type Output = core::sync::atomic::AtomicU16;
345}
346
347#[cfg(target_has_atomic = "32")]
348impl AsAtomic for u32 {
349    type Output = core::sync::atomic::AtomicU32;
350}
351
352#[cfg(target_has_atomic = "64")]
353impl AsAtomic for u64 {
354    type Output = core::sync::atomic::AtomicU64;
355}