secure_gate/random/
dynamic_rng.rs1use crate::Dynamic;
3use rand::rand_core::OsError;
4use rand::rngs::OsRng;
5use rand::TryRngCore;
6
7#[cfg(any(feature = "encoding-hex", feature = "encoding-base64"))]
8use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
9#[cfg(any(
10 feature = "encoding-hex",
11 feature = "encoding-base64",
12 feature = "encoding-bech32"
13))]
14use bech32::{Bech32, Bech32m, Hrp};
15#[cfg(feature = "encoding-hex")]
16use hex;
17
18pub struct DynamicRng(Dynamic<Vec<u8>>);
38
39impl DynamicRng {
40 pub fn generate(len: usize) -> Self {
54 let mut bytes = vec![0u8; len];
55 OsRng
56 .try_fill_bytes(&mut bytes)
57 .expect("OsRng failed — this should never happen on supported platforms");
58 Self(Dynamic::from(bytes))
59 }
60
61 pub fn try_generate(len: usize) -> Result<Self, OsError> {
76 let mut bytes = vec![0u8; len];
77 OsRng
78 .try_fill_bytes(&mut bytes)
79 .map(|_| Self(Dynamic::from(bytes)))
80 }
81
82 #[inline(always)]
84 pub fn expose_secret(&self) -> &[u8] {
85 self.0.expose_secret()
86 }
87
88 #[inline(always)]
90 pub const fn len(&self) -> usize {
91 self.0.len()
92 }
93
94 #[inline(always)]
96 pub const fn is_empty(&self) -> bool {
97 self.0.is_empty()
98 }
99
100 #[inline(always)]
102 pub fn into_inner(self) -> Dynamic<Vec<u8>> {
103 self.0
104 }
105}
106
107impl core::fmt::Debug for DynamicRng {
108 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109 f.write_str("[REDACTED]")
110 }
111}
112
113#[cfg(all(feature = "rand", feature = "encoding-bech32"))]
114impl DynamicRng {
115 pub fn into_bech32(self, hrp: &str) -> crate::encoding::bech32::Bech32String {
123 let hrp = Hrp::parse(hrp).expect("invalid HRP");
124 let encoded = bech32::encode::<Bech32>(hrp, self.expose_secret())
125 .expect("encoding valid random bytes cannot fail");
126
127 crate::encoding::bech32::Bech32String::new_unchecked(
128 encoded,
129 crate::encoding::bech32::EncodingVariant::Bech32,
130 )
131 }
132
133 pub fn to_bech32(&self, hrp: &str) -> crate::encoding::bech32::Bech32String {
135 let hrp = Hrp::parse(hrp).expect("invalid HRP");
136 let encoded = bech32::encode::<Bech32>(hrp, self.expose_secret())
137 .expect("encoding valid random bytes cannot fail");
138
139 crate::encoding::bech32::Bech32String::new_unchecked(
140 encoded,
141 crate::encoding::bech32::EncodingVariant::Bech32,
142 )
143 }
144
145 pub fn into_bech32m(self, hrp: &str) -> crate::encoding::bech32::Bech32String {
153 let hrp = Hrp::parse(hrp).expect("invalid HRP");
154 let encoded = bech32::encode::<Bech32m>(hrp, self.expose_secret())
155 .expect("encoding valid random bytes cannot fail");
156
157 crate::encoding::bech32::Bech32String::new_unchecked(
158 encoded,
159 crate::encoding::bech32::EncodingVariant::Bech32m,
160 )
161 }
162
163 pub fn to_bech32m(&self, hrp: &str) -> crate::encoding::bech32::Bech32String {
165 let hrp = Hrp::parse(hrp).expect("invalid HRP");
166 let encoded = bech32::encode::<Bech32m>(hrp, self.expose_secret())
167 .expect("encoding valid random bytes cannot fail");
168
169 crate::encoding::bech32::Bech32String::new_unchecked(
170 encoded,
171 crate::encoding::bech32::EncodingVariant::Bech32m,
172 )
173 }
174}
175
176#[cfg(all(feature = "rand", feature = "encoding-hex"))]
177impl DynamicRng {
178 pub fn into_hex(self) -> crate::encoding::hex::HexString {
182 let hex_str = hex::encode(self.expose_secret());
183 crate::encoding::hex::HexString::new_unchecked(hex_str)
184 }
185
186 pub fn to_hex(&self) -> crate::encoding::hex::HexString {
188 let hex_str = hex::encode(self.expose_secret());
189 crate::encoding::hex::HexString::new_unchecked(hex_str)
190 }
191}
192
193#[cfg(all(feature = "rand", feature = "encoding-base64"))]
194impl DynamicRng {
195 pub fn into_base64(self) -> crate::encoding::base64::Base64String {
199 let encoded = URL_SAFE_NO_PAD.encode(self.expose_secret());
200 crate::encoding::base64::Base64String::new_unchecked(encoded)
201 }
202
203 pub fn to_base64(&self) -> crate::encoding::base64::Base64String {
205 let encoded = URL_SAFE_NO_PAD.encode(self.expose_secret());
206 crate::encoding::base64::Base64String::new_unchecked(encoded)
207 }
208}
209
210impl From<DynamicRng> for Dynamic<Vec<u8>> {
211 #[inline(always)]
227 fn from(rng: DynamicRng) -> Self {
228 rng.into_inner()
229 }
230}