lib_q_random/
saturnin_det.rs1#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5
6use lib_q_saturnin::SaturninStream;
7
8use crate::Result;
9use crate::kt128_expander::DOMAIN_LIBQ_DET_SATURNIN;
10
11const NONCE_LEN: usize = 16;
12const KEY_LEN: usize = 32;
13const CHUNK: usize = 4096;
14
15pub struct SaturninDetExpander {
17 key: [u8; KEY_LEN],
18 nonce: [u8; NONCE_LEN],
19 keystream: Vec<u8>,
20 position: usize,
21 counter: u64,
22}
23
24impl SaturninDetExpander {
25 pub fn from_seed_32(seed: [u8; 32]) -> Result<Self> {
31 let mut nonce = [0u8; NONCE_LEN];
32 let domain = DOMAIN_LIBQ_DET_SATURNIN;
33 let copy_len = core::cmp::min(NONCE_LEN, domain.len());
34 nonce[..copy_len].copy_from_slice(&domain[..copy_len]);
35
36 let stream = SaturninStream::new();
37 let keystream = stream
38 .generate_keystream(&seed, &nonce, CHUNK)
39 .map_err(|_| crate::Error::platform_rng_failed("saturnin"))?;
40
41 Ok(Self {
42 key: seed,
43 nonce,
44 keystream: keystream.to_vec(),
45 position: 0,
46 counter: 0,
47 })
48 }
49
50 fn refill(&mut self) -> Result<()> {
51 self.counter = self.counter.wrapping_add(1);
52 let mut nonce = self.nonce;
53 nonce[8..16].copy_from_slice(&self.counter.to_le_bytes());
54 let stream = SaturninStream::new();
55 let chunk = stream
56 .generate_keystream(&self.key, &nonce, CHUNK)
57 .map_err(|_| crate::Error::platform_rng_failed("saturnin"))?;
58 self.keystream = chunk.to_vec();
59 self.position = 0;
60 Ok(())
61 }
62
63 pub fn fill_bytes(&mut self, dest: &mut [u8]) -> Result<()> {
69 let mut remaining = dest.len();
70 let mut offset = 0;
71 while remaining > 0 {
72 if self.position >= self.keystream.len() {
73 self.refill()?;
74 }
75 let available = self.keystream.len() - self.position;
76 let to_copy = core::cmp::min(remaining, available);
77 dest[offset..offset + to_copy]
78 .copy_from_slice(&self.keystream[self.position..self.position + to_copy]);
79 self.position += to_copy;
80 offset += to_copy;
81 remaining -= to_copy;
82 }
83 Ok(())
84 }
85}
86
87#[cfg(feature = "alloc")]
89pub struct SaturninDeterministicEntropySource {
90 expander: SaturninDetExpander,
91 quality: f64,
92}
93
94#[cfg(feature = "alloc")]
95impl SaturninDeterministicEntropySource {
96 pub fn new(seed: [u8; 32]) -> Result<Self> {
102 Ok(Self {
103 expander: SaturninDetExpander::from_seed_32(seed)?,
104 quality: 0.0,
105 })
106 }
107}
108
109#[cfg(feature = "alloc")]
110impl crate::traits::EntropySource for SaturninDeterministicEntropySource {
111 fn get_entropy(&mut self, dest: &mut [u8]) -> Result<()> {
112 self.expander.fill_bytes(dest)
113 }
114
115 fn initialize(&mut self, config: &crate::traits::EntropyConfig) -> Result<()> {
116 let _ = config;
117 Ok(())
118 }
119
120 fn is_available(&self) -> bool {
121 true
122 }
123
124 fn quality(&self) -> f64 {
125 self.quality
126 }
127
128 fn name(&self) -> &'static str {
129 "Saturnin Deterministic Entropy Source"
130 }
131
132 fn source_type(&self) -> crate::traits::EntropySourceType {
133 crate::traits::EntropySourceType::Deterministic
134 }
135
136 fn max_entropy_per_call(&self) -> Option<usize> {
137 None
138 }
139}
140
141#[cfg(all(test, feature = "deterministic-saturnin"))]
142mod tests {
143 use super::*;
144 use crate::kt128_expander::Kt128Expander;
145
146 #[test]
147 fn saturnin_det_differs_from_kt128_det() {
148 let seed = [3u8; 32];
149 let mut sat = SaturninDetExpander::from_seed_32(seed).expect("saturnin");
150 let mut kt = Kt128Expander::from_det_seed_32(seed);
151 let mut a = [0u8; 64];
152 let mut b = [0u8; 64];
153 sat.fill_bytes(&mut a).expect("fill");
154 kt.fill_bytes(&mut b);
155 assert_ne!(a, b);
156 }
157}