#[cfg(any(test, feature = "dev"))]
pub use test::test_rng;
use typenum::Unsigned;
use crate::{constants::CollisionResistanceBytes, hashing::Digest, random::CryptoRngCore};
pub type BaseRng = rand::rngs::StdRng;
pub type Seed = [u8; CollisionResistanceBytes::USIZE];
pub trait SeedableRng:
CryptoRngCore + rand::SeedableRng<Seed: AsRef<[u8]> + From<Digest>> + Clone + Send
{
#[inline]
fn from_tagged_seed(seed: Self::Seed, tag: impl AsRef<[u8]>) -> Self {
let seed = crate::hashing::hash(&[seed.as_ref(), tag.as_ref()]);
<Self as rand::SeedableRng>::from_seed(seed.into())
}
#[inline]
fn from_seed(seed: Self::Seed) -> Self {
<Self as rand::SeedableRng>::from_seed(seed)
}
#[inline]
fn from_rng<R: rand::RngCore>(mut rng: R) -> Result<Self, rand::Error> {
<Self as rand::SeedableRng>::from_rng(&mut rng)
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand::RngCore::fill_bytes(self, dest)
}
}
impl<T> SeedableRng for T where
T: CryptoRngCore + rand::SeedableRng<Seed = super::Seed> + Clone + Send
{
}
#[cfg(any(test, feature = "dev"))]
pub mod test {
use std::{cell::UnsafeCell, rc::Rc};
use rand::{CryptoRng, RngCore, SeedableRng};
use crate::random::BaseRng;
pub fn test_rng() -> TestRng {
let rng = TEST_RNG_KEY.with(|t| t.clone());
TestRng { rng }
}
thread_local!(
static TEST_RNG_KEY: Rc<UnsafeCell<BaseRng>> = {
let rng = match std::env::var("ASYNC_MPC_NON_DETERMINISTIC_TESTS") {
Ok(_) => BaseRng::from_rng(rand::thread_rng()).unwrap_or_else(|err|
panic!("could not initialize test_rng: {err}")),
Err(_) => {
let thread = std::thread::current();
let seed = crate::hashing::hash(&[thread.name().unwrap_or("async_mpc_test").as_bytes()]);
BaseRng::from_seed(seed.into())
}
};
Rc::new(UnsafeCell::new(rng))
});
#[derive(Clone, Debug)]
pub struct TestRng {
rng: Rc<UnsafeCell<BaseRng>>,
}
impl Default for TestRng {
fn default() -> TestRng {
test_rng()
}
}
impl RngCore for TestRng {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
let rng = unsafe { &mut *self.rng.get() };
rng.next_u32()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
let rng = unsafe { &mut *self.rng.get() };
rng.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let rng = unsafe { &mut *self.rng.get() };
rng.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
let rng = unsafe { &mut *self.rng.get() };
rng.try_fill_bytes(dest)
}
}
impl CryptoRng for TestRng {}
}