use std::io::Cursor;
use std::mem::size_of;
use crate::tiny_keccak::{Xof, Hasher, cshake::{CShake, cshake128, cshake256}};
use byteorder::{ReadBytesExt, LittleEndian};
pub struct DRBG {
shaker: CShake
}
impl DRBG {
pub fn new(seed: &[u8], customization: Option<&[u8]>) -> DRBG {
let mut shaker = if seed.len() > 16 {
CShake::v256(None, customization)
} else {
CShake::v128(None, customization)
};
shaker.absorb(seed);
DRBG { shaker }
}
fn drbg(&mut self, output: &mut [u8]){
self.shaker.squeeze(output);
}
pub fn sampler16(&mut self, range: u32) -> u16 {
let range_divisor = 0x10000u32 / range;
let range_limit = range * range_divisor;
let mut rnd: [u8; 2] = [0, 0];
while {
self.drbg(&mut rnd);
u8_to_u16!(rnd) as u32 >= range_limit
} {};
(u8_to_u16!(rnd) as u32 / range_divisor) as u16
}
pub fn sampler16_2(&mut self, range: u32) -> u16 {
let mut rnd: [u8; 2] = [0, 0];
self.drbg(&mut rnd);
(u8_to_u16!(rnd) as u32 & (range - 1)) as u16
}
pub fn sampler16_2_once(xlen: usize, seed: &[u8], range: u32) -> Vec<u16> {
let mut x = vec![0u8; xlen * size_of::<u16>()];
if seed.len() > 16 {
cshake256(x.as_mut_slice(), seed, None, None);
} else {
cshake128(x.as_mut_slice(), seed, None, None);
}
let mut a: Vec<u16> = Vec::with_capacity(xlen);
let mut rdr = Cursor::new(x);
for _ in 0..xlen {
a.push(rdr.read_u16::<LittleEndian>().unwrap() & (range - 1) as u16);
}
a
}
}