1use rand::rngs::OsRng;
2use rand::{RngCore, SeedableRng, TryRngCore};
3use rand_xoshiro::Xoshiro256PlusPlus;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6#[derive(Debug)]
7pub struct NonceError(String);
8
9impl std::fmt::Display for NonceError {
10 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11 f.write_str(&self.0)
12 }
13}
14
15impl std::error::Error for NonceError {}
16
17pub struct NonceGenerator {
18 rng: Xoshiro256PlusPlus,
19}
20
21impl NonceGenerator {
22 pub fn new() -> Result<Self, NonceError> {
23 let mut seed = [0u8; 32];
24 let mut rng = OsRng;
25 rng.try_fill_bytes(&mut seed)
26 .map_err(|e| NonceError(format!("OsRng unavailable: {e}")))?;
27 Ok(Self {
28 rng: Xoshiro256PlusPlus::from_seed(seed),
29 })
30 }
31
32 pub fn next_u64(&mut self) -> u64 {
33 self.rng.next_u64()
34 }
35}
36
37pub struct AtomicNonceGenerator {
43 counter: AtomicU64,
44 entropy_base: AtomicU64,
45}
46
47impl AtomicNonceGenerator {
48 pub const fn new() -> Self {
49 Self {
50 counter: AtomicU64::new(1),
51 entropy_base: AtomicU64::new(0),
52 }
53 }
54
55 pub fn init(&self) -> Result<(), NonceError> {
56 if self.entropy_base.load(Ordering::Relaxed) == 0 {
57 let mut buf = [0u8; 8];
58 let mut rng = OsRng;
59 rng.try_fill_bytes(&mut buf)
60 .map_err(|e| NonceError(format!("OsRng unavailable: {e}")))?;
61 let entropy = u64::from_le_bytes(buf);
62 let _ =
63 self.entropy_base
64 .compare_exchange(0, entropy, Ordering::SeqCst, Ordering::Relaxed);
65 }
66 Ok(())
67 }
68
69 #[inline]
70 pub fn next_u64(&self) -> Result<u64, NonceError> {
71 let base = self.entropy_base.load(Ordering::Relaxed);
72 let base = if base == 0 {
73 self.init()?;
74 self.entropy_base.load(Ordering::Relaxed)
75 } else {
76 base
77 };
78
79 let count = self.counter.fetch_add(1, Ordering::Relaxed);
80 Ok(base.wrapping_add(count))
81 }
82}
83
84impl Default for AtomicNonceGenerator {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90#[cfg(test)]
91#[path = "nonce_tests.rs"]
92mod tests;