secure_gate/random/dynamic_random.rs
1use crate::Dynamic;
2use rand::rand_core::OsError;
3use rand::rngs::OsRng;
4use rand::TryRngCore;
5
6/// Heap-allocated cryptographically secure random bytes with encoding methods.
7///
8/// This is a newtype over `Dynamic<Vec<u8>>` for semantic clarity.
9/// Like `FixedRandom`, guarantees freshness via RNG construction.
10///
11/// Requires the `rand` feature.
12///
13/// Supports direct encoding to Hex, Base64, Bech32, and Bech32m via convenience methods.
14///
15/// # Examples
16///
17/// ```
18/// # #[cfg(feature = "rand")]
19/// # {
20/// use secure_gate::{random::DynamicRandom, ExposeSecret};
21/// let random = DynamicRandom::generate(64);
22/// assert_eq!(random.len(), 64);
23/// # }
24/// ```
25pub struct DynamicRandom(pub(crate) Dynamic<Vec<u8>>);
26
27impl DynamicRandom {
28 /// Generate fresh random bytes of the specified length.
29 ///
30 /// Panics if the RNG fails.
31 ///
32 /// # Example
33 ///
34 /// ```
35 /// # #[cfg(feature = "rand")]
36 /// # {
37 /// use secure_gate::random::DynamicRandom;
38 /// let random = DynamicRandom::generate(128);
39 /// # }
40 /// ```
41 pub fn generate(len: usize) -> Self {
42 let mut bytes = vec![0u8; len];
43 OsRng
44 .try_fill_bytes(&mut bytes)
45 .expect("OsRng failed — this should never happen on supported platforms");
46 Self(Dynamic::from(bytes))
47 }
48
49 /// Try to generate fresh random bytes of the specified length.
50 ///
51 /// Returns an error if the RNG fails.
52 ///
53 /// # Example
54 ///
55 /// ```
56 /// # #[cfg(feature = "rand")]
57 /// # {
58 /// use secure_gate::random::DynamicRandom;
59 /// let random: Result<DynamicRandom, rand::rand_core::OsError> = DynamicRandom::try_generate(64);
60 /// assert!(random.is_ok());
61 /// # }
62 /// ```
63 pub fn try_generate(len: usize) -> Result<Self, OsError> {
64 let mut bytes = vec![0u8; len];
65 OsRng
66 .try_fill_bytes(&mut bytes)
67 .map(|_| Self(Dynamic::from(bytes)))
68 }
69
70 /// Consume and return the inner `Dynamic<Vec<u8>>`.
71 #[inline(always)]
72 pub fn into_inner(self) -> Dynamic<Vec<u8>> {
73 self.0
74 }
75}
76
77/// Debug implementation (always redacted).
78impl core::fmt::Debug for DynamicRandom {
79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80 f.write_str("[REDACTED]")
81 }
82}
83
84impl From<DynamicRandom> for Dynamic<Vec<u8>> {
85 /// Convert a `DynamicRandom` to `Dynamic`, transferring ownership.
86 ///
87 /// This preserves all security guarantees. The `DynamicRandom` type
88 /// ensures the value came from secure RNG, and this conversion
89 /// transfers that value to `Dynamic` without exposing bytes.
90 ///
91 /// # Example
92 ///
93 /// ```
94 /// # #[cfg(feature = "rand")]
95 /// # {
96 /// use secure_gate::{Dynamic, random::DynamicRandom};
97 /// let random: Dynamic<Vec<u8>> = DynamicRandom::generate(64).into();
98 /// # }
99 /// ```
100 #[inline(always)]
101 fn from(rng: DynamicRandom) -> Self {
102 rng.into_inner()
103 }
104}