use crate::error::RandomError;
pub trait RandomSource {
fn fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), RandomError>;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct SystemRandom;
impl SystemRandom {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl RandomSource for SystemRandom {
fn fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), RandomError> {
getrandom::fill(dest).map_err(|_| RandomError)
}
}
#[cfg(any(test, feature = "test-utils"))]
#[derive(Debug, Clone)]
pub struct FixedBytesRandom {
bytes: Vec<u8>,
pos: usize,
}
#[cfg(any(test, feature = "test-utils"))]
impl FixedBytesRandom {
#[must_use]
pub fn new(bytes: Vec<u8>) -> Self {
assert!(
!bytes.is_empty(),
"FixedBytesRandom needs at least one byte"
);
Self { bytes, pos: 0 }
}
}
#[cfg(any(test, feature = "test-utils"))]
impl RandomSource for FixedBytesRandom {
fn fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), RandomError> {
for slot in dest.iter_mut() {
*slot = self.bytes[self.pos % self.bytes.len()];
self.pos += 1;
}
Ok(())
}
}
#[cfg(any(test, feature = "test-utils"))]
#[derive(Debug, Default, Clone, Copy)]
pub struct AlwaysFailRandom;
#[cfg(any(test, feature = "test-utils"))]
impl RandomSource for AlwaysFailRandom {
fn fill_bytes(&mut self, _dest: &mut [u8]) -> Result<(), RandomError> {
Err(RandomError)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn system_random_fills_distinct_buffers() {
let mut r = SystemRandom::new();
let mut a = [0u8; 32];
let mut b = [0u8; 32];
r.fill_bytes(&mut a).unwrap();
r.fill_bytes(&mut b).unwrap();
assert_ne!(a, b);
assert!(a.iter().any(|&x| x != 0));
}
#[test]
fn always_fail_random_errors() {
let mut r = AlwaysFailRandom;
let mut buf = [0u8; 4];
assert_eq!(r.fill_bytes(&mut buf), Err(RandomError));
}
#[test]
fn fixed_bytes_random_is_deterministic() {
let mut r = FixedBytesRandom::new(vec![1, 2, 3]);
let mut buf = [0u8; 5];
r.fill_bytes(&mut buf).unwrap();
assert_eq!(buf, [1, 2, 3, 1, 2]);
}
}