use bincode::{Decode, Encode};
use rand_core::{CryptoRng, RngCore};
use crate::bits::Bit;
use crate::constants::PRNG_CONTEXT;
const SEED_LEN: usize = blake3::KEY_LEN;
#[derive(Debug, Default, Encode, Decode, Clone)]
pub struct Seed([u8; blake3::KEY_LEN]);
impl Seed {
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut bytes = [0u8; SEED_LEN];
rng.fill_bytes(&mut bytes[..]);
Self(bytes)
}
}
const BUF_LEN: usize = 64;
#[derive(Clone)]
pub struct BitPRNG {
reader: blake3::OutputReader,
buf: [u8; BUF_LEN],
bit_index: usize,
}
impl BitPRNG {
fn fill_buf(&mut self) {
self.reader.fill(&mut self.buf);
}
}
impl BitPRNG {
pub fn seeded(seed: &Seed) -> Self {
let mut hasher = blake3::Hasher::new_keyed(&seed.0);
hasher.update(PRNG_CONTEXT.as_bytes());
Self::from_hasher(hasher)
}
pub fn from_hasher(hasher: blake3::Hasher) -> Self {
let reader = hasher.finalize_xof();
let mut out = Self {
reader,
buf: [0; BUF_LEN],
bit_index: 0,
};
out.fill_buf();
out
}
pub fn next_bit(&mut self) -> Bit {
if self.bit_index >= 8 * BUF_LEN {
self.bit_index = 0;
self.fill_buf();
}
let index = self.bit_index;
self.bit_index += 1;
Bit::select_u8(self.buf[index / 8], index % 8)
}
pub fn next_trit(&mut self) -> u8 {
loop {
let a = u64::from(self.next_bit()) as u8;
let b = u64::from(self.next_bit()) as u8;
let trit = (a << 1) | b;
if trit < 3 {
return trit;
}
}
}
}