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 write!(f, "Seed")
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 let seed = Seed::from(1);
129 let mut rng: Rng = seed.rng();
130
131 let mut data = [0u8; 2];
132
133 rng.fill_bytes(&mut data);
134
135 assert_eq!([62u8, 186u8], data);
136 }
137}