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