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