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 {
40 counter: AtomicU64,
41 entropy_base: AtomicU64,
42}
43
44impl AtomicNonceGenerator {
45 pub const fn new() -> Self {
46 Self {
47 counter: AtomicU64::new(1),
48 entropy_base: AtomicU64::new(0),
49 }
50 }
51
52 pub fn init(&self) -> Result<(), NonceError> {
53 if self.entropy_base.load(Ordering::Relaxed) == 0 {
54 let mut buf = [0u8; 8];
55 let mut rng = OsRng;
56 rng.try_fill_bytes(&mut buf)
57 .map_err(|e| NonceError(format!("OsRng unavailable: {e}")))?;
58 let entropy = u64::from_le_bytes(buf);
59 let _ =
60 self.entropy_base
61 .compare_exchange(0, entropy, Ordering::SeqCst, Ordering::Relaxed);
62 }
63 Ok(())
64 }
65
66 #[inline]
67 pub fn next_u64(&self) -> Result<u64, NonceError> {
68 let base = self.entropy_base.load(Ordering::Relaxed);
69 let base = if base == 0 {
70 self.init()?;
71 self.entropy_base.load(Ordering::Relaxed)
72 } else {
73 base
74 };
75
76 let count = self.counter.fetch_add(1, Ordering::Relaxed);
77 Ok(base.wrapping_add(count))
78 }
79}
80
81impl Default for AtomicNonceGenerator {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[cfg(test)]
88#[path = "nonce_tests.rs"]
89mod tests;