use crate::word::Word;
use crate::{crypto::Hasher, word::CompositeWord};
use alloc::vec;
use alloc::vec::Vec;
use core::{array, fmt::Debug};
use zeroize::{Zeroize, Zeroizing};
pub trait RandomGenerator: Debug {
fn fill_bytes(&mut self, out: &mut [u8]);
fn next_byte(&mut self) -> u8 {
return self.next_bytes::<1>()[0];
}
fn next_bytes<const N: usize>(&mut self) -> [u8; N] {
let mut out = [0u8; N];
self.fill_bytes(&mut out);
return out;
}
fn next_bytes_vec(&mut self, n: usize) -> Vec<u8> {
let mut out = vec![0u8; n];
self.fill_bytes(&mut out);
return out;
}
}
pub trait GeneratesRandom<T> {
fn next(&mut self) -> T;
fn next_vec(&mut self, n: usize) -> Vec<T> {
return (0..n).into_iter().map(|_| self.next()).collect();
}
}
impl<R: RandomGenerator, W: Word> GeneratesRandom<W> for R {
fn next(&mut self) -> W {
let mut b = W::Bytes::default();
self.fill_bytes(b.as_mut());
return W::from_le_bytes(b);
}
}
impl<R: RandomGenerator, W: Word, const N: usize> GeneratesRandom<CompositeWord<W, N>> for R {
fn next(&mut self) -> CompositeWord<W, N> {
let mut bs = [W::Bytes::default(); N];
bs.iter_mut().for_each(|b| self.fill_bytes(b.as_mut()));
return CompositeWord::<W, N>::from_le_bytes(bs);
}
}
pub trait PseudoRandomGenerator: RandomGenerator {
fn new(seed: &[u8]) -> Self;
}
#[derive(Debug)]
pub struct HashPRG<H: Hasher> {
hasher: H,
key: Zeroizing<H::Digest>,
counter: u64,
buf: Zeroizing<H::Digest>,
pos: usize,
}
impl<H: Hasher> PseudoRandomGenerator for HashPRG<H> {
fn new(seed: &[u8]) -> Self {
assert!(
H::DIGEST_SIZE > 0,
"Hasher digest size must be greater than zero"
);
let mut hasher = H::new();
hasher.update(seed);
let key = hasher.finalize();
return Self {
hasher,
key: Zeroizing::new(key),
counter: 0,
buf: Zeroizing::new(H::Digest::default()),
pos: H::DIGEST_SIZE,
};
}
}
impl<H: Hasher> HashPRG<H> {
pub fn available_bytes(&self) -> usize {
return H::DIGEST_SIZE - self.pos;
}
pub fn is_buffer_empty(&self) -> bool {
return self.pos == H::DIGEST_SIZE;
}
pub fn refill_buffer(&mut self) {
self.hasher.update(self.key.as_ref());
self.hasher.update(&self.counter.to_le_bytes());
self.buf = Zeroizing::new(self.hasher.finalize());
self.counter += 1;
self.pos = 0;
}
}
impl<H: Hasher> RandomGenerator for HashPRG<H> {
fn fill_bytes(&mut self, out: &mut [u8]) {
if self.is_buffer_empty() {
self.refill_buffer();
}
if out.len() < self.available_bytes() {
out.copy_from_slice(&self.buf.as_ref()[self.pos..self.pos + out.len()]);
self.pos += out.len();
return;
}
let mut written = 0;
while written < out.len() {
if self.is_buffer_empty() {
self.refill_buffer();
}
let available = self.available_bytes();
let needed = out.len() - written;
let n = core::cmp::min(available, needed);
out[written..written + n].copy_from_slice(&self.buf.as_ref()[self.pos..self.pos + n]);
self.pos += n;
written += n;
}
}
fn next_byte(&mut self) -> u8 {
if self.is_buffer_empty() {
self.refill_buffer();
}
let byte = self.buf.as_ref()[self.pos];
self.pos += 1;
return byte;
}
}
pub trait Seed:
AsMut<[u8]> + AsRef<[u8]> + Clone + PartialEq + Eq + Default + Zeroize + Debug + Sized
{
}
impl<T> Seed for T where
T: AsMut<[u8]> + AsRef<[u8]> + Clone + PartialEq + Eq + Default + Zeroize + Debug + Sized
{
}
impl<R: RandomGenerator, S: Seed> GeneratesRandom<[S; 3]> for R {
fn next(&mut self) -> [S; 3] {
let mut out: [S; 3] = array::from_fn(|_| S::default());
for seed in out.iter_mut() {
self.fill_bytes(seed.as_mut());
}
return out;
}
}