use super::fork::ForkGuard;
use super::{Error, NONCE_SIZE};
const NONCE_MASK_96: u128 = (1_u128 << 96) - 1;
pub(crate) struct NonceGen {
base: u128,
counter: u64,
fork_guard: ForkGuard,
}
impl NonceGen {
pub(crate) fn new() -> Result<Self, Error> {
Ok(Self {
base: os_salt()?,
counter: 0,
fork_guard: ForkGuard::capture(),
})
}
pub(crate) fn next(&mut self) -> Result<[u8; NONCE_SIZE], Error> {
if !self.fork_guard.unchanged() {
self.resalt()?;
}
let value = self.base.wrapping_add(u128::from(self.counter)) & NONCE_MASK_96;
self.counter = self.counter.wrapping_add(1);
if self.counter == 0 {
self.resalt()?;
}
let bytes = value.to_le_bytes();
let mut nonce = [0_u8; NONCE_SIZE];
nonce.copy_from_slice(&bytes[..NONCE_SIZE]);
Ok(nonce)
}
fn resalt(&mut self) -> Result<(), Error> {
self.base = os_salt()?;
self.counter = 0;
self.fork_guard = ForkGuard::capture();
Ok(())
}
}
fn os_salt() -> Result<u128, Error> {
let mut bytes = [0_u8; 16];
getrandom::fill(&mut bytes[..NONCE_SIZE]).map_err(|_| Error::OsEntropy)?;
Ok(u128::from_le_bytes(bytes) & NONCE_MASK_96)
}