asjeeves_encryption/
seed.rs1use std::fmt;
4use std::sync::Arc;
5use std::sync::atomic::{AtomicU64, Ordering};
6
7use rand_chacha::ChaCha20Rng;
8use rand_core::{CryptoRng, RngCore, SeedableRng};
9
10static STREAM: AtomicU64 = AtomicU64::new(0);
11
12#[derive(Clone)]
26pub struct Seed(Arc<[u8; 32]>);
27
28pub struct Rng(ChaCha20Rng);
30
31impl AsRef<ChaCha20Rng> for Rng {
32 fn as_ref(&self) -> &ChaCha20Rng {
33 &self.0
34 }
35}
36
37impl AsMut<ChaCha20Rng> for Rng {
38 fn as_mut(&mut self) -> &mut ChaCha20Rng {
39 &mut self.0
40 }
41}
42
43impl CryptoRng for Rng {}
44
45impl fmt::Debug for Rng {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.debug_struct("Rng").finish_non_exhaustive()
49 }
50}
51
52impl RngCore for Rng {
53 fn next_u32(&mut self) -> u32 {
54 self.0.next_u32()
55 }
56
57 fn next_u64(&mut self) -> u64 {
58 self.0.next_u64()
59 }
60
61 fn fill_bytes(&mut self, dest: &mut [u8]) {
62 self.0.fill_bytes(dest);
63 }
64
65 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
66 self.0.try_fill_bytes(dest)
67 }
68}
69
70impl Seed {
71 pub fn rng(&self) -> Rng {
74 let local_stream = STREAM.fetch_add(1, Ordering::Relaxed);
75
76 let mut rng = ChaCha20Rng::from_seed(*self.0);
77
78 rng.set_stream(local_stream);
79
80 Rng(rng)
81 }
82
83 fn reset_stream() {
84 STREAM.store(0, Ordering::SeqCst)
85 }
86}
87
88impl fmt::Debug for Seed {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 f.debug_struct("Seed").finish_non_exhaustive()
91 }
92}
93
94impl Default for Seed {
95 fn default() -> Self {
96 let mut rng = ChaCha20Rng::from_entropy();
97 let mut seed = [0u8; 32];
98
99 rng.fill_bytes(&mut seed);
100
101 let seed = Arc::new(seed);
102
103 Self(seed)
104 }
105}
106
107impl From<u64> for Seed {
108 fn from(value: u64) -> Self {
109 let mut rng = ChaCha20Rng::seed_from_u64(value);
110 let mut seed = [0u8; 32];
111
112 rng.fill_bytes(&mut seed);
113
114 let seed = Arc::new(seed);
115
116 Seed::reset_stream();
117
118 Self(seed)
119 }
120}
121
122#[cfg(test)]
123mod test {
124 use super::*;
125
126 #[test]
127 fn it_generates_a_random_number() {
128 {
129 let seed = Seed::from(1);
130 let mut rng: Rng = seed.rng();
131
132 let mut data = [0u8; 2];
133
134 rng.fill_bytes(&mut data);
135
136 assert_eq!([62u8, 186u8], data);
137 }
138
139 {
140 let seed = Seed::from(1);
141 let mut rng: Rng = seed.rng();
142
143 let mut data = [0u8; 2];
144
145 rng.try_fill_bytes(&mut data).unwrap();
146
147 assert_eq!([62u8, 186u8], data);
148 }
149
150 {
151 let seed = Seed::from(1);
152 let mut rng: Rng = seed.rng();
153
154 let datum: u32 = rng.next_u32();
155
156 assert_eq!(649050686, datum);
157 }
158
159 {
160 let seed = Seed::from(1);
161 let mut rng: Rng = seed.rng();
162
163 let datum: u64 = rng.next_u64();
164
165 assert_eq!(15639741899973048894, datum);
166 }
167 }
168
169 #[test]
170 fn it_obfuscates_sensitive_data_when_debugged() {
171 let seed = Seed::default();
172
173 let dbg = format!("{:?}", seed);
174
175 assert_eq!("Seed { .. }", dbg);
176
177 let dbg = format!("{:?}", seed.rng());
178
179 assert_eq!("Rng { .. }", dbg);
180 }
181}