use crate::error::OrionIdError;
pub(crate) type RandomFill = fn(&mut [u8]) -> Result<(), OrionIdError>;
pub(crate) fn default_random_fill(out: &mut [u8]) -> Result<(), OrionIdError> {
getrandom::getrandom(out).map_err(|_| OrionIdError::RandomFailure)
}
pub(crate) struct RandomPool {
buffer: Vec<u8>,
cursor: usize,
fill: RandomFill,
}
impl RandomPool {
pub(crate) fn new(size_bytes: usize, fill: RandomFill) -> Self {
let buffer = vec![0u8; size_bytes];
let cursor = size_bytes; Self {
buffer,
cursor,
fill,
}
}
pub(crate) fn fill_into(&mut self, out: &mut [u8]) -> Result<(), OrionIdError> {
let length = out.len();
if length > self.buffer.len() {
return (self.fill)(out);
}
if self.cursor + length > self.buffer.len() {
self.refill()?;
}
let start = self.cursor;
let end = start + length;
out.copy_from_slice(&self.buffer[start..end]);
self.cursor = end;
Ok(())
}
pub(crate) fn next_10_bits(&mut self) -> Result<u32, OrionIdError> {
let mut tmp = [0u8; 2];
self.fill_into(&mut tmp)?;
Ok((((u32::from(tmp[0])) << 8) | u32::from(tmp[1])) & 0x03ff)
}
fn refill(&mut self) -> Result<(), OrionIdError> {
(self.fill)(&mut self.buffer)?;
self.cursor = 0;
Ok(())
}
}