use crate::rng::{Generator, SecureGenerator};
use chachacha::{BUF_LEN_U64, ChaCha8Djb, SEED_LEN_U8};
use core::fmt;
use core::mem::MaybeUninit;
pub struct SecureRng {
buf: [u64; BUF_LEN_U64],
index: usize,
internal: ChaCha8Djb,
}
impl fmt::Debug for SecureRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("all `SecureRng` fields are private")
}
}
impl SecureGenerator for SecureRng {
#[inline]
fn fill_bytes(&mut self, dst: &mut [u8]) {
self.internal.fill(dst);
}
}
impl Generator for SecureRng {
#[inline]
fn try_new() -> Result<Self, getrandom::Error> {
#[allow(clippy::uninit_assumed_init, invalid_value)]
let mut state = unsafe { MaybeUninit::<[u8; SEED_LEN_U8]>::uninit().assume_init() };
getrandom::fill(&mut state)?;
let mut internal = ChaCha8Djb::from(state);
let buf = internal.get_block_u64();
let index = 0;
Ok(Self {
buf,
index,
internal,
})
}
#[cfg_attr(feature = "inline", inline)]
fn u64(&mut self) -> u64 {
if self.index >= self.buf.len() {
self.index = 0;
self.internal.fill_block_u64(&mut self.buf);
}
let ret = unsafe { *self.buf.get_unchecked(self.index) };
self.index += 1;
ret
}
}