1use crate::rng::{Generator, SecureGenerator};
2use chachacha::{BUF_LEN_U64, ChaCha8Djb, SEED_LEN_U8};
3use core::fmt;
4use core::mem::MaybeUninit;
5
6pub struct SecureRng {
12 buf: [u64; BUF_LEN_U64],
13 index: usize,
14 internal: ChaCha8Djb,
15}
16
17impl fmt::Debug for SecureRng {
18 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19 f.write_str("all `SecureRng` fields are private")
20 }
21}
22
23impl SecureGenerator for SecureRng {
24 #[inline]
25 fn fill_bytes(&mut self, dst: &mut [u8]) {
26 self.internal.fill(dst);
29 }
30}
31
32impl Generator for SecureRng {
33 #[inline]
34 fn try_new() -> Result<Self, getrandom::Error> {
35 #[allow(clippy::uninit_assumed_init, invalid_value)]
38 let mut state = unsafe { MaybeUninit::<[u8; SEED_LEN_U8]>::uninit().assume_init() };
39 getrandom::fill(&mut state)?;
40 let mut internal = ChaCha8Djb::from(state);
41 let buf = internal.get_block_u64();
42 let index = 0;
43 Ok(Self {
44 buf,
45 index,
46 internal,
47 })
48 }
49
50 #[cfg_attr(feature = "inline", inline)]
51 fn u64(&mut self) -> u64 {
52 if self.index >= self.buf.len() {
54 self.index = 0;
55 self.internal.fill_block_u64(&mut self.buf);
56 }
57 let ret = unsafe { *self.buf.get_unchecked(self.index) };
60 self.index += 1;
61 ret
62 }
63}