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}