Files

88 lines
2.0 KiB
Rust

//! Random generation utilities
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use crate::time::monotonic_time;
// use crate::device::monotonic_timestamp;
const BUFFER_SIZE: usize = 1024;
struct RandomState {
data: [u8; BUFFER_SIZE],
pos: usize,
last_state: u32,
}
impl RandomState {
fn new(seed: u32) -> Self {
Self {
data: [0; BUFFER_SIZE],
pos: BUFFER_SIZE,
last_state: seed,
}
}
fn next(&mut self) -> u32 {
let mut x = self.last_state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
self.last_state = x;
x
}
fn fill_buf(&mut self) {
self.pos = 0;
for i in (0..self.data.len()).step_by(4) {
let v = self.next();
self.data[i..i + 4].copy_from_slice(&v.to_ne_bytes());
}
}
fn read_buf(&mut self, buf: &mut [u8]) {
let mut rem = buf.len();
let mut pos = 0;
while rem != 0 {
if self.pos == BUFFER_SIZE {
self.fill_buf();
}
let count = core::cmp::min(rem, BUFFER_SIZE - self.pos);
buf[pos..pos + count].copy_from_slice(&self.data[self.pos..self.pos + count]);
self.pos += count;
rem -= count;
pos += count;
}
}
}
static RANDOM_STATE: OneTimeInit<IrqSafeSpinlock<RandomState>> = OneTimeInit::new();
/// Fills `buf` with random bytes
pub fn read_unsecure(buf: &mut [u8]) {
let state = RANDOM_STATE.get();
state.lock().read_buf(buf)
}
pub fn range(a: u64, b: u64) -> u64 {
assert!(b > a);
let mut bytes = [0; 8];
read_unsecure(&mut bytes);
let v = u64::from_ne_bytes(bytes) % (b - a);
a + v
}
/// Initializes the random generator state
pub fn init() {
let now = monotonic_time();
let random_seed = now.subsec_nanos().wrapping_add(now.seconds());
let mut state = RandomState::new(random_seed as u32);
state.fill_buf();
RANDOM_STATE.init(IrqSafeSpinlock::new(state));
}