secure_gate/traits/
expose_secret.rs

1//! # Secret Exposure Traits
2//!
3//! This module defines traits for polymorphic secret access with controlled mutability and metadata.
4//! These traits enable writing generic code that works across different secret wrapper types
5//! while enforcing security guarantees.
6//!
7//! ## Key Traits
8//!
9//! - [`ExposeSecret`]: Read-only access to secret values including metadata
10//!
11//! ## Security Model
12//!
13//! - **Full access**: Core wrappers ([`Fixed`], [`Dynamic`]) implement [`ExposeSecret`], with mutable variants implementing [`ExposeSecretMut`]
14//! - **Read-only**: Random ([`FixedRandom`], [`DynamicRandom`]) and encoding wrappers
15//!   only implement [`ExposeSecret`] to prevent mutation
16//! - **Zero-cost**: All implementations use `#[inline(always)]`
17//!
18/// ## Usage
19///
20/// Import these traits to access secret values and their metadata ergonomically.
21use crate::{Dynamic, Fixed};
22
23#[cfg(feature = "rand")]
24use crate::random::{DynamicRandom, FixedRandom};
25
26#[cfg(feature = "encoding-hex")]
27use crate::encoding::hex::HexString;
28
29#[cfg(feature = "encoding-base64")]
30use crate::encoding::base64::Base64String;
31
32#[cfg(feature = "encoding-bech32")]
33use crate::encoding::bech32::Bech32String;
34
35/// Trait for read-only access to secrets, including metadata.
36///
37/// Import this to enable `.expose_secret()`, `.len()`, and `.is_empty()`.
38/// For mutable access, see [`super::ExposeSecretMut`].
39pub trait ExposeSecret {
40    /// The inner secret type being exposed.
41    ///
42    /// This can be a sized type (like `[u8; N]`) or unsized (like `str` or `[u8]`).
43    type Inner: ?Sized;
44
45    /// Expose the secret for read-only access.
46    fn expose_secret(&self) -> &Self::Inner;
47
48    /// Returns the length of the secret.
49    fn len(&self) -> usize;
50
51    /// Returns true if the secret is empty.
52    #[inline(always)]
53    fn is_empty(&self) -> bool {
54        self.len() == 0
55    }
56}
57
58// ============================================================================
59// Core Wrapper Implementations
60// ============================================================================
61
62/// Implementation for [`Fixed<[T; N]>`] - provides full read/write access for arrays.
63///
64/// [`Fixed`] is a core wrapper that allows both reading and mutation of secrets.
65/// This implementation directly accesses the inner field.
66impl<const N: usize, T> ExposeSecret for Fixed<[T; N]> {
67    type Inner = [T; N];
68
69    #[inline(always)]
70    fn expose_secret(&self) -> &[T; N] {
71        &self.0
72    }
73
74    #[inline(always)]
75    fn len(&self) -> usize {
76        N
77    }
78}
79
80/// Implementation for [`Dynamic<String>`] - provides full read/write access.
81///
82/// [`Dynamic<String>`] is a core wrapper that allows both reading and mutation of secrets.
83/// This implementation directly accesses the inner field.
84impl ExposeSecret for Dynamic<String> {
85    type Inner = String;
86
87    #[inline(always)]
88    fn expose_secret(&self) -> &String {
89        &self.0
90    }
91
92    #[inline(always)]
93    fn len(&self) -> usize {
94        self.0.len()
95    }
96}
97
98/// Implementation for [`Dynamic<Vec<T>>`] - provides full read/write access.
99///
100/// [`Dynamic<Vec<T>>`] is a core wrapper that allows both reading and mutation of secrets.
101/// This implementation directly accesses the inner field.
102impl<T> ExposeSecret for Dynamic<Vec<T>> {
103    type Inner = Vec<T>;
104
105    #[inline(always)]
106    fn expose_secret(&self) -> &Vec<T> {
107        &self.0
108    }
109
110    #[inline(always)]
111    fn len(&self) -> usize {
112        self.0.len()
113    }
114}
115
116/// Implementation for [`Fixed<CloneableArrayInner<N>>`] - exposes the inner wrapper.
117#[cfg(feature = "zeroize")]
118impl<const N: usize> ExposeSecret
119    for crate::Fixed<crate::cloneable::array::CloneableArrayInner<N>>
120{
121    type Inner = crate::cloneable::array::CloneableArrayInner<N>;
122
123    #[inline(always)]
124    fn expose_secret(&self) -> &crate::cloneable::array::CloneableArrayInner<N> {
125        &self.0
126    }
127
128    #[inline(always)]
129    fn len(&self) -> usize {
130        N
131    }
132}
133
134// ============================================================================
135// Random Wrapper Implementations (Read-Only Only)
136// ============================================================================
137
138/// Implementation for [`Dynamic<CloneableStringInner>`] - exposes the inner wrapper.
139#[cfg(feature = "zeroize")]
140impl ExposeSecret for crate::Dynamic<crate::cloneable::string::CloneableStringInner> {
141    type Inner = crate::cloneable::string::CloneableStringInner;
142
143    #[inline(always)]
144    fn expose_secret(&self) -> &crate::cloneable::string::CloneableStringInner {
145        &self.0
146    }
147
148    #[inline(always)]
149    fn len(&self) -> usize {
150        self.0 .0.len()
151    }
152}
153
154/// Implementation for [`Dynamic<CloneableVecInner>`] - exposes the inner wrapper.
155#[cfg(feature = "zeroize")]
156impl ExposeSecret for crate::Dynamic<crate::cloneable::vec::CloneableVecInner> {
157    type Inner = crate::cloneable::vec::CloneableVecInner;
158
159    #[inline(always)]
160    fn expose_secret(&self) -> &crate::cloneable::vec::CloneableVecInner {
161        &self.0
162    }
163
164    #[inline(always)]
165    fn len(&self) -> usize {
166        self.0 .0.len()
167    }
168}
169
170/// Implementation for [`FixedRandom<N>`] - read-only access.
171///
172/// Random wrappers only provide read-only access to prevent invalidation of the
173/// randomly generated secret. The `Inner` type is `[u8]` (slice) for compatibility
174/// with `SecureRandom` trait bounds.
175#[cfg(feature = "rand")]
176impl<const N: usize> ExposeSecret for FixedRandom<N> {
177    type Inner = [u8];
178
179    #[inline(always)]
180    fn expose_secret(&self) -> &[u8] {
181        &self.0 .0
182    }
183
184    #[inline(always)]
185    fn len(&self) -> usize {
186        N
187    }
188}
189
190/// Implementation for [`DynamicRandom`] - read-only access.
191///
192/// Random wrappers only provide read-only access to prevent invalidation of the
193/// randomly generated secret. The `Inner` type is `[u8]` (slice) for compatibility
194/// with `SecureRandom` trait bounds.
195#[cfg(feature = "rand")]
196impl ExposeSecret for DynamicRandom {
197    type Inner = [u8];
198
199    #[inline(always)]
200    fn expose_secret(&self) -> &[u8] {
201        &self.0 .0
202    }
203
204    #[inline(always)]
205    fn len(&self) -> usize {
206        self.0 .0.len()
207    }
208}
209
210// ============================================================================
211// Encoding Wrapper Implementations (Read-Only Only)
212// ============================================================================
213
214/// Implementation for [`HexString`] - read-only access.
215///
216/// Encoding wrappers only provide read-only access to prevent invalidation of
217/// validation invariants. The `Inner` type is `str` since encoded strings are
218/// always valid UTF-8.
219#[cfg(feature = "encoding-hex")]
220impl ExposeSecret for HexString {
221    type Inner = str;
222
223    #[inline(always)]
224    fn expose_secret(&self) -> &str {
225        self.0.expose_secret().as_str()
226    }
227
228    #[inline(always)]
229    fn len(&self) -> usize {
230        self.0.len()
231    }
232}
233
234/// Implementation for [`Base64String`] - read-only access.
235///
236/// Encoding wrappers only provide read-only access to prevent invalidation of
237/// validation invariants. The `Inner` type is `str` since encoded strings are
238/// always valid UTF-8.
239#[cfg(feature = "encoding-base64")]
240impl ExposeSecret for Base64String {
241    type Inner = str;
242
243    #[inline(always)]
244    fn expose_secret(&self) -> &str {
245        self.0.expose_secret().as_str()
246    }
247
248    #[inline(always)]
249    fn len(&self) -> usize {
250        self.0.len()
251    }
252}
253
254/// Implementation for [`Bech32String`] - read-only access.
255///
256/// Encoding wrappers only provide read-only access to prevent invalidation of
257/// validation invariants. The `Inner` type is `str` since encoded strings are
258/// always valid UTF-8.
259#[cfg(feature = "encoding-bech32")]
260impl ExposeSecret for Bech32String {
261    type Inner = str;
262
263    #[inline(always)]
264    fn expose_secret(&self) -> &str {
265        self.inner.expose_secret().as_str()
266    }
267
268    #[inline(always)]
269    fn len(&self) -> usize {
270        self.inner.0.len()
271    }
272}
273
274// ============================================================================
275// Specific Implementations for Test Types
276// ============================================================================
277
278/// Implementation for [`Fixed<u32>`] - provides access for test compatibility.
279impl ExposeSecret for Fixed<u32> {
280    type Inner = u32;
281
282    #[inline(always)]
283    fn expose_secret(&self) -> &u32 {
284        &self.0
285    }
286
287    #[inline(always)]
288    fn len(&self) -> usize {
289        1
290    }
291}