#![forbid(unsafe_code)]
mod helpers;
mod oxirng;
mod read;
mod reseeding;
mod thread_rng;
pub use oxirng::{OxiRng, OxiRng12, OxiRng8};
pub use reseeding::ReseedingRng;
pub use helpers::{
check_entropy, random_bool, random_bool_with_rng, random_bytes, random_nonce, random_range,
random_range_to, random_range_unbiased, random_u128, random_u32, random_u64, reseed, shuffle,
weighted_choice, weighted_choice_with_rng,
};
#[cfg(feature = "std")]
pub use thread_rng::with_thread_rng;
#[cfg(test)]
pub mod test_rng {
use rand_chacha::ChaCha20Rng;
use rand_core::{SeedableRng, TryCryptoRng, TryRng};
use oxicrypto_core::{CryptoError, Rng};
pub struct TestRng(ChaCha20Rng);
impl TestRng {
pub fn from_seed(seed: [u8; 32]) -> Self {
Self(ChaCha20Rng::from_seed(seed))
}
}
impl Rng for TestRng {
fn fill(&mut self, dst: &mut [u8]) -> Result<(), CryptoError> {
use rand_core::TryRng;
self.0.try_fill_bytes(dst).map_err(|_| CryptoError::Rng)
}
}
impl TryRng for TestRng {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
self.0.try_next_u32()
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
self.0.try_next_u64()
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
self.0.try_fill_bytes(dest)
}
}
impl TryCryptoRng for TestRng {}
}
#[cfg(test)]
mod tests {
use super::*;
use oxicrypto_core::Rng;
#[test]
fn test_rng_deterministic() {
use test_rng::TestRng;
let seed = [42u8; 32];
let mut rng1 = TestRng::from_seed(seed);
let mut rng2 = TestRng::from_seed(seed);
let mut out1 = [0u8; 64];
let mut out2 = [0u8; 64];
rng1.fill(&mut out1).expect("TestRng fill 1 failed");
rng2.fill(&mut out2).expect("TestRng fill 2 failed");
assert_eq!(out1, out2, "Same seed must produce same output");
}
#[test]
fn test_rng_different_seeds_differ() {
use test_rng::TestRng;
let mut rng_a = TestRng::from_seed([1u8; 32]);
let mut rng_b = TestRng::from_seed([2u8; 32]);
let mut out_a = [0u8; 64];
let mut out_b = [0u8; 64];
rng_a.fill(&mut out_a).expect("TestRng fill a failed");
rng_b.fill(&mut out_b).expect("TestRng fill b failed");
assert_ne!(
out_a, out_b,
"Different seeds must produce different output"
);
}
}