use std::cell::RefCell; use itertools::izip; use rand::{distributions::Uniform, thread_rng, CryptoRng, Rng, RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use rand_distr::Distribution; use crate::utils::WithLocal; thread_local! { pub(crate) static DEFAULT_RNG: RefCell = RefCell::new(DefaultSecureRng::new_seeded([0u8;32])); } pub(crate) trait NewWithSeed { type Seed; fn new_with_seed(seed: Self::Seed) -> Self; } pub trait RandomGaussianDist where M: ?Sized, { type Parameters: ?Sized; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M); } pub trait RandomUniformDist where M: ?Sized, { type Parameters: ?Sized; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M); } pub(crate) struct DefaultSecureRng { rng: ChaCha8Rng, } impl DefaultSecureRng { pub fn new_seeded(seed: ::Seed) -> DefaultSecureRng { let rng = ChaCha8Rng::from_seed(seed); DefaultSecureRng { rng } } pub fn new() -> DefaultSecureRng { let rng = ChaCha8Rng::from_entropy(); DefaultSecureRng { rng } } pub fn fill_bytes(&mut self, a: &mut [u8; 32]) { self.rng.fill_bytes(a); } } impl NewWithSeed for DefaultSecureRng { type Seed = ::Seed; fn new_with_seed(seed: Self::Seed) -> Self { DefaultSecureRng::new_seeded(seed) } } impl RandomUniformDist for DefaultSecureRng { type Parameters = usize; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut usize) { *container = self.rng.gen_range(0..*parameters); } } impl RandomUniformDist<[u8]> for DefaultSecureRng { type Parameters = u8; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u8]) { self.rng.fill_bytes(container); } } impl RandomUniformDist<[u32]> for DefaultSecureRng { type Parameters = u32; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) { izip!( (&mut self.rng).sample_iter(Uniform::new(0, parameters)), container.iter_mut() ) .for_each(|(from, to)| { *to = from; }); } } impl RandomUniformDist<[u64]> for DefaultSecureRng { type Parameters = u64; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) { izip!( (&mut self.rng).sample_iter(Uniform::new(0, parameters)), container.iter_mut() ) .for_each(|(from, to)| { *to = from; }); } } impl RandomGaussianDist for DefaultSecureRng { type Parameters = u64; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u64) { let o = rand_distr::Normal::new(0.0, 3.2f64) .unwrap() .sample(&mut self.rng) .round(); // let o = 0.0f64; let is_neg = o.is_sign_negative() && o != 0.0; if is_neg { *container = parameters - (o.abs() as u64); } else { *container = o as u64; } } } impl RandomGaussianDist for DefaultSecureRng { type Parameters = u32; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u32) { let o = rand_distr::Normal::new(0.0, 3.2f32) .unwrap() .sample(&mut self.rng) .round(); // let o = 0.0f32; let is_neg = o.is_sign_negative() && o != 0.0; if is_neg { *container = parameters - (o.abs() as u32); } else { *container = o as u32; } } } impl RandomGaussianDist<[u64]> for DefaultSecureRng { type Parameters = u64; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) { izip!( rand_distr::Normal::new(0.0, 3.2f64) .unwrap() .sample_iter(&mut self.rng), container.iter_mut() ) .for_each(|(oi, v)| { let oi = oi.round(); let is_neg = oi.is_sign_negative() && oi != 0.0; if is_neg { *v = parameters - (oi.abs() as u64); } else { *v = oi as u64; } }); } } impl RandomGaussianDist<[u32]> for DefaultSecureRng { type Parameters = u32; fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) { izip!( rand_distr::Normal::new(0.0, 3.2f32) .unwrap() .sample_iter(&mut self.rng), container.iter_mut() ) .for_each(|(oi, v)| { let oi = oi.round(); let is_neg = oi.is_sign_negative() && oi != 0.0; if is_neg { *v = parameters - (oi.abs() as u32); } else { *v = oi as u32; } }); } } impl WithLocal for DefaultSecureRng { fn with_local(func: F) -> R where F: Fn(&Self) -> R, { DEFAULT_RNG.with_borrow(|r| func(r)) } fn with_local_mut(func: F) -> R where F: Fn(&mut Self) -> R, { DEFAULT_RNG.with_borrow_mut(|r| func(r)) } }