use rand::{RngCore, SeedableRng, Rng};
use rand_chacha::ChaCha20Rng;
use std::sync::{Arc, Mutex};
use lazy_static::lazy_static;
lazy_static! {
static ref SECURE_RNG: Arc<Mutex<SecureRng>> = Arc::new(Mutex::new(SecureRng::new()));
}
#[derive(Debug)]
pub struct SecureRng {
rng: ChaCha20Rng,
}
impl SecureRng {
pub fn new() -> Self {
let mut seed = [0u8; 32];
rand::thread_rng().fill_bytes(&mut seed);
let rng = ChaCha20Rng::from_seed(seed);
Self { rng }
}
pub fn random_bytes(&mut self, len: usize) -> Vec<u8> {
let mut bytes = vec![0u8; len];
self.rng.fill_bytes(&mut bytes);
bytes
}
pub fn random_u64(&mut self) -> u64 {
self.rng.next_u64()
}
pub fn random_u32(&mut self) -> u32 {
self.rng.next_u32()
}
pub fn random_usize(&mut self) -> usize {
self.rng.gen::<usize>()
}
pub fn random_f64(&mut self) -> f64 {
self.rng.gen::<f64>()
}
pub fn random_in_range(&mut self, min: i64, max: i64) -> i64 {
self.rng.gen_range(min..max)
}
pub fn random_bool(&mut self) -> bool {
self.rng.gen::<bool>()
}
pub fn shuffle<T>(&mut self, slice: &mut [T]) {
use rand::seq::SliceRandom;
slice.shuffle(&mut self.rng);
}
pub fn reseed(&mut self) {
let mut seed = [0u8; 32];
rand::thread_rng().fill_bytes(&mut seed);
self.rng = ChaCha20Rng::from_seed(seed);
}
}
pub fn random_bytes(len: usize) -> Vec<u8> {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_bytes(len),
Err(_) => vec![0u8; len], }
}
pub fn random_u64() -> u64 {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_u64(),
Err(_) => 0, }
}
pub fn random_u32() -> u32 {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_u32(),
Err(_) => 0, }
}
pub fn random_usize() -> usize {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_usize(),
Err(_) => 0, }
}
pub fn random_f64() -> f64 {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_f64(),
Err(_) => 0.0, }
}
pub fn random_in_range(min: i64, max: i64) -> i64 {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_in_range(min, max),
Err(_) => min, }
}
pub fn random_bool() -> bool {
match SECURE_RNG.lock() {
Ok(mut rng) => rng.random_bool(),
Err(_) => false, }
}
pub fn shuffle<T>(slice: &mut [T]) {
if let Ok(mut rng) = SECURE_RNG.lock() {
rng.shuffle(slice);
}
}
pub fn reseed() {
if let Ok(mut rng) = SECURE_RNG.lock() {
rng.reseed();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_random_bytes() {
let bytes1 = random_bytes(32);
let bytes2 = random_bytes(32);
assert_eq!(bytes1.len(), 32);
assert_eq!(bytes2.len(), 32);
assert_ne!(bytes1, bytes2);
}
#[test]
fn test_random_in_range() {
let min = 10;
let max = 100;
for _ in 0..100 {
let value = random_in_range(min, max);
assert!(value >= min);
assert!(value < max);
}
}
#[test]
fn test_shuffle() {
let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut shuffled = original.clone();
shuffle(&mut shuffled);
assert_ne!(original, shuffled);
let mut sorted = shuffled.clone();
sorted.sort();
assert_eq!(sorted, original);
}
}