Add TryRngCore and TryCryptoRng traits (#1424)

This reworks fallibility, replacing the fixed `Error` type.
This commit is contained in:
Artyom Pavlov 2024-05-08 16:10:32 +03:00 committed by GitHub
parent 1f818787ca
commit fba5521f0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 641 additions and 759 deletions

View File

@ -92,7 +92,7 @@ compiler versions will be compatible. This is especially true of Rand's
experimental `simd_support` feature. experimental `simd_support` feature.
Rand supports limited functionality in `no_std` mode (enabled via Rand supports limited functionality in `no_std` mode (enabled via
`default-features = false`). In this case, `OsRng` and `from_entropy` are `default-features = false`). In this case, `OsRng` and `from_os_rng` are
unavailable (unless `getrandom` is enabled), large parts of `seq` are unavailable (unless `getrandom` is enabled), large parts of `seq` are
unavailable (unless `alloc` is enabled), and `thread_rng` and `random` are unavailable (unless `alloc` is enabled), and `thread_rng` and `random` are
unavailable. unavailable.

View File

@ -32,7 +32,7 @@ macro_rules! distr_int {
($fnn:ident, $ty:ty, $distr:expr) => { ($fnn:ident, $ty:ty, $distr:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
b.iter(|| { b.iter(|| {
@ -52,7 +52,7 @@ macro_rules! distr_nz_int {
($fnn:ident, $tynz:ty, $ty:ty, $distr:expr) => { ($fnn:ident, $tynz:ty, $ty:ty, $distr:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
b.iter(|| { b.iter(|| {
@ -72,7 +72,7 @@ macro_rules! distr_float {
($fnn:ident, $ty:ty, $distr:expr) => { ($fnn:ident, $ty:ty, $distr:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
b.iter(|| { b.iter(|| {
@ -92,7 +92,7 @@ macro_rules! distr_duration {
($fnn:ident, $distr:expr) => { ($fnn:ident, $distr:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
b.iter(|| { b.iter(|| {
@ -114,7 +114,7 @@ macro_rules! distr {
($fnn:ident, $ty:ty, $distr:expr) => { ($fnn:ident, $ty:ty, $distr:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
b.iter(|| { b.iter(|| {
@ -191,7 +191,7 @@ macro_rules! gen_range_int {
($fnn:ident, $ty:ident, $low:expr, $high:expr) => { ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
b.iter(|| { b.iter(|| {
let mut high = $high; let mut high = $high;
@ -199,7 +199,7 @@ macro_rules! gen_range_int {
for _ in 0..RAND_BENCH_N { for _ in 0..RAND_BENCH_N {
accum = accum.wrapping_add(rng.gen_range($low..high)); accum = accum.wrapping_add(rng.gen_range($low..high));
// force recalculation of range each time // force recalculation of range each time
high = high.wrapping_add(1) & core::$ty::MAX; high = high.wrapping_add(1) & $ty::MAX;
} }
accum accum
}); });
@ -230,7 +230,7 @@ macro_rules! gen_range_float {
($fnn:ident, $ty:ident, $low:expr, $high:expr) => { ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
b.iter(|| { b.iter(|| {
let mut high = $high; let mut high = $high;
@ -267,7 +267,7 @@ macro_rules! uniform_sample {
($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => { ($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let low = black_box($low); let low = black_box($low);
let high = black_box($high); let high = black_box($high);
b.iter(|| { b.iter(|| {
@ -286,7 +286,7 @@ macro_rules! uniform_inclusive {
($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => { ($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let low = black_box($low); let low = black_box($low);
let high = black_box($high); let high = black_box($high);
b.iter(|| { b.iter(|| {
@ -306,7 +306,7 @@ macro_rules! uniform_single {
($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => { ($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let low = black_box($low); let low = black_box($low);
let high = black_box($high); let high = black_box($high);
b.iter(|| { b.iter(|| {

View File

@ -15,13 +15,14 @@ const RAND_BENCH_N: u64 = 1000;
const BYTES_LEN: usize = 1024; const BYTES_LEN: usize = 1024;
use core::mem::size_of; use core::mem::size_of;
use rand_chacha::rand_core::UnwrapErr;
use test::{black_box, Bencher}; use test::{black_box, Bencher};
use rand::prelude::*; use rand::prelude::*;
use rand::rngs::ReseedingRng; use rand::rngs::ReseedingRng;
use rand::rngs::{mock::StepRng, OsRng}; use rand::rngs::{mock::StepRng, OsRng};
use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng}; use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng};
use rand_pcg::{Pcg32, Pcg64, Pcg64Mcg, Pcg64Dxsm}; use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg};
macro_rules! gen_bytes { macro_rules! gen_bytes {
($fnn:ident, $gen:expr) => { ($fnn:ident, $gen:expr) => {
@ -41,17 +42,17 @@ macro_rules! gen_bytes {
} }
gen_bytes!(gen_bytes_step, StepRng::new(0, 1)); gen_bytes!(gen_bytes_step, StepRng::new(0, 1));
gen_bytes!(gen_bytes_pcg32, Pcg32::from_entropy()); gen_bytes!(gen_bytes_pcg32, Pcg32::from_os_rng());
gen_bytes!(gen_bytes_pcg64, Pcg64::from_entropy()); gen_bytes!(gen_bytes_pcg64, Pcg64::from_os_rng());
gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_entropy()); gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_os_rng());
gen_bytes!(gen_bytes_pcg64dxsm, Pcg64Dxsm::from_entropy()); gen_bytes!(gen_bytes_pcg64dxsm, Pcg64Dxsm::from_os_rng());
gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_entropy()); gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_os_rng());
gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy()); gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_os_rng());
gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy()); gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_os_rng());
gen_bytes!(gen_bytes_std, StdRng::from_entropy()); gen_bytes!(gen_bytes_std, StdRng::from_os_rng());
#[cfg(feature = "small_rng")] #[cfg(feature = "small_rng")]
gen_bytes!(gen_bytes_small, SmallRng::from_thread_rng()); gen_bytes!(gen_bytes_small, SmallRng::from_thread_rng());
gen_bytes!(gen_bytes_os, OsRng); gen_bytes!(gen_bytes_os, UnwrapErr(OsRng));
gen_bytes!(gen_bytes_thread, thread_rng()); gen_bytes!(gen_bytes_thread, thread_rng());
macro_rules! gen_uint { macro_rules! gen_uint {
@ -62,7 +63,7 @@ macro_rules! gen_uint {
b.iter(|| { b.iter(|| {
let mut accum: $ty = 0; let mut accum: $ty = 0;
for _ in 0..RAND_BENCH_N { for _ in 0..RAND_BENCH_N {
accum = accum.wrapping_add(rng.gen::<$ty>()); accum = accum.wrapping_add(rng.random::<$ty>());
} }
accum accum
}); });
@ -72,40 +73,40 @@ macro_rules! gen_uint {
} }
gen_uint!(gen_u32_step, u32, StepRng::new(0, 1)); gen_uint!(gen_u32_step, u32, StepRng::new(0, 1));
gen_uint!(gen_u32_pcg32, u32, Pcg32::from_entropy()); gen_uint!(gen_u32_pcg32, u32, Pcg32::from_os_rng());
gen_uint!(gen_u32_pcg64, u32, Pcg64::from_entropy()); gen_uint!(gen_u32_pcg64, u32, Pcg64::from_os_rng());
gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_entropy()); gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_os_rng());
gen_uint!(gen_u32_pcg64dxsm, u32, Pcg64Dxsm::from_entropy()); gen_uint!(gen_u32_pcg64dxsm, u32, Pcg64Dxsm::from_os_rng());
gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_entropy()); gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_os_rng());
gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_entropy()); gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_os_rng());
gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_entropy()); gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_os_rng());
gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); gen_uint!(gen_u32_std, u32, StdRng::from_os_rng());
#[cfg(feature = "small_rng")] #[cfg(feature = "small_rng")]
gen_uint!(gen_u32_small, u32, SmallRng::from_thread_rng()); gen_uint!(gen_u32_small, u32, SmallRng::from_thread_rng());
gen_uint!(gen_u32_os, u32, OsRng); gen_uint!(gen_u32_os, u32, UnwrapErr(OsRng));
gen_uint!(gen_u32_thread, u32, thread_rng()); gen_uint!(gen_u32_thread, u32, thread_rng());
gen_uint!(gen_u64_step, u64, StepRng::new(0, 1)); gen_uint!(gen_u64_step, u64, StepRng::new(0, 1));
gen_uint!(gen_u64_pcg32, u64, Pcg32::from_entropy()); gen_uint!(gen_u64_pcg32, u64, Pcg32::from_os_rng());
gen_uint!(gen_u64_pcg64, u64, Pcg64::from_entropy()); gen_uint!(gen_u64_pcg64, u64, Pcg64::from_os_rng());
gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_entropy()); gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_os_rng());
gen_uint!(gen_u64_pcg64dxsm, u64, Pcg64Dxsm::from_entropy()); gen_uint!(gen_u64_pcg64dxsm, u64, Pcg64Dxsm::from_os_rng());
gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_entropy()); gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_os_rng());
gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_entropy()); gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_os_rng());
gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_entropy()); gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_os_rng());
gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); gen_uint!(gen_u64_std, u64, StdRng::from_os_rng());
#[cfg(feature = "small_rng")] #[cfg(feature = "small_rng")]
gen_uint!(gen_u64_small, u64, SmallRng::from_thread_rng()); gen_uint!(gen_u64_small, u64, SmallRng::from_thread_rng());
gen_uint!(gen_u64_os, u64, OsRng); gen_uint!(gen_u64_os, u64, UnwrapErr(OsRng));
gen_uint!(gen_u64_thread, u64, thread_rng()); gen_uint!(gen_u64_thread, u64, thread_rng());
macro_rules! init_gen { macro_rules! init_gen {
($fnn:ident, $gen:ident) => { ($fnn:ident, $gen:ident) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = Pcg32::from_entropy(); let mut rng = Pcg32::from_os_rng();
b.iter(|| { b.iter(|| {
let r2 = $gen::from_rng(&mut rng).unwrap(); let r2 = $gen::from_rng(&mut rng);
r2 r2
}); });
} }
@ -125,7 +126,7 @@ macro_rules! reseeding_bytes {
($fnn:ident, $thresh:expr) => { ($fnn:ident, $thresh:expr) => {
#[bench] #[bench]
fn $fnn(b: &mut Bencher) { fn $fnn(b: &mut Bencher) {
let mut rng = ReseedingRng::new(ChaCha20Core::from_entropy(), $thresh * 1024, OsRng); let mut rng = ReseedingRng::new(ChaCha20Core::from_os_rng(), $thresh * 1024, OsRng);
let mut buf = [0u8; RESEEDING_BYTES_LEN]; let mut buf = [0u8; RESEEDING_BYTES_LEN];
b.iter(|| { b.iter(|| {
for _ in 0..RESEEDING_BENCH_N { for _ in 0..RESEEDING_BENCH_N {

View File

@ -20,7 +20,7 @@ use rand_pcg::{Pcg32, Pcg64Mcg};
#[bench] #[bench]
fn misc_gen_bool_const(b: &mut Bencher) { fn misc_gen_bool_const(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg32::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let mut accum = true; let mut accum = true;
for _ in 0..RAND_BENCH_N { for _ in 0..RAND_BENCH_N {
@ -32,7 +32,7 @@ fn misc_gen_bool_const(b: &mut Bencher) {
#[bench] #[bench]
fn misc_gen_bool_var(b: &mut Bencher) { fn misc_gen_bool_var(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg32::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let mut accum = true; let mut accum = true;
let mut p = 0.18; let mut p = 0.18;
@ -46,7 +46,7 @@ fn misc_gen_bool_var(b: &mut Bencher) {
#[bench] #[bench]
fn misc_gen_ratio_const(b: &mut Bencher) { fn misc_gen_ratio_const(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg32::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let mut accum = true; let mut accum = true;
for _ in 0..RAND_BENCH_N { for _ in 0..RAND_BENCH_N {
@ -58,7 +58,7 @@ fn misc_gen_ratio_const(b: &mut Bencher) {
#[bench] #[bench]
fn misc_gen_ratio_var(b: &mut Bencher) { fn misc_gen_ratio_var(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg32::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let mut accum = true; let mut accum = true;
for i in 2..(RAND_BENCH_N as u32 + 2) { for i in 2..(RAND_BENCH_N as u32 + 2) {
@ -70,7 +70,7 @@ fn misc_gen_ratio_var(b: &mut Bencher) {
#[bench] #[bench]
fn misc_bernoulli_const(b: &mut Bencher) { fn misc_bernoulli_const(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg32::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let d = Bernoulli::new(0.18).unwrap(); let d = Bernoulli::new(0.18).unwrap();
let mut accum = true; let mut accum = true;
@ -83,7 +83,7 @@ fn misc_bernoulli_const(b: &mut Bencher) {
#[bench] #[bench]
fn misc_bernoulli_var(b: &mut Bencher) { fn misc_bernoulli_var(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg32::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let mut accum = true; let mut accum = true;
let mut p = 0.18; let mut p = 0.18;
@ -99,7 +99,7 @@ fn misc_bernoulli_var(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u16_iter_repeat(b: &mut Bencher) { fn gen_1kb_u16_iter_repeat(b: &mut Bencher) {
use core::iter; use core::iter;
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let v: Vec<u16> = iter::repeat(()).map(|()| rng.random()).take(512).collect(); let v: Vec<u16> = iter::repeat(()).map(|()| rng.random()).take(512).collect();
v v
@ -109,7 +109,7 @@ fn gen_1kb_u16_iter_repeat(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u16_sample_iter(b: &mut Bencher) { fn gen_1kb_u16_sample_iter(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let v: Vec<u16> = Standard.sample_iter(&mut rng).take(512).collect(); let v: Vec<u16> = Standard.sample_iter(&mut rng).take(512).collect();
v v
@ -119,7 +119,7 @@ fn gen_1kb_u16_sample_iter(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u16_gen_array(b: &mut Bencher) { fn gen_1kb_u16_gen_array(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
// max supported array length is 32! // max supported array length is 32!
let v: [[u16; 32]; 16] = rng.random(); let v: [[u16; 32]; 16] = rng.random();
@ -130,7 +130,7 @@ fn gen_1kb_u16_gen_array(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u16_fill(b: &mut Bencher) { fn gen_1kb_u16_fill(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
let mut buf = [0u16; 512]; let mut buf = [0u16; 512];
b.iter(|| { b.iter(|| {
rng.fill(&mut buf[..]); rng.fill(&mut buf[..]);
@ -142,7 +142,7 @@ fn gen_1kb_u16_fill(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u64_iter_repeat(b: &mut Bencher) { fn gen_1kb_u64_iter_repeat(b: &mut Bencher) {
use core::iter; use core::iter;
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let v: Vec<u64> = iter::repeat(()).map(|()| rng.random()).take(128).collect(); let v: Vec<u64> = iter::repeat(()).map(|()| rng.random()).take(128).collect();
v v
@ -152,7 +152,7 @@ fn gen_1kb_u64_iter_repeat(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u64_sample_iter(b: &mut Bencher) { fn gen_1kb_u64_sample_iter(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect(); let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect();
v v
@ -162,7 +162,7 @@ fn gen_1kb_u64_sample_iter(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u64_gen_array(b: &mut Bencher) { fn gen_1kb_u64_gen_array(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
b.iter(|| { b.iter(|| {
// max supported array length is 32! // max supported array length is 32!
let v: [[u64; 32]; 4] = rng.random(); let v: [[u64; 32]; 4] = rng.random();
@ -173,7 +173,7 @@ fn gen_1kb_u64_gen_array(b: &mut Bencher) {
#[bench] #[bench]
fn gen_1kb_u64_fill(b: &mut Bencher) { fn gen_1kb_u64_fill(b: &mut Bencher) {
let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); let mut rng = Pcg64Mcg::from_rng(&mut thread_rng());
let mut buf = [0u64; 128]; let mut buf = [0u64; 128];
b.iter(|| { b.iter(|| {
rng.fill(&mut buf[..]); rng.fill(&mut buf[..]);

View File

@ -25,7 +25,7 @@ const RAND_BENCH_N: u64 = 1000;
#[bench] #[bench]
fn seq_shuffle_100(b: &mut Bencher) { fn seq_shuffle_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
let x: &mut [usize] = &mut [1; 100]; let x: &mut [usize] = &mut [1; 100];
b.iter(|| { b.iter(|| {
x.shuffle(&mut rng); x.shuffle(&mut rng);
@ -35,7 +35,7 @@ fn seq_shuffle_100(b: &mut Bencher) {
#[bench] #[bench]
fn seq_slice_choose_1_of_1000(b: &mut Bencher) { fn seq_slice_choose_1_of_1000(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
let x: &mut [usize] = &mut [1; 1000]; let x: &mut [usize] = &mut [1; 1000];
for (i, r) in x.iter_mut().enumerate() { for (i, r) in x.iter_mut().enumerate() {
*r = i; *r = i;
@ -54,7 +54,7 @@ macro_rules! seq_slice_choose_multiple {
($name:ident, $amount:expr, $length:expr) => { ($name:ident, $amount:expr, $length:expr) => {
#[bench] #[bench]
fn $name(b: &mut Bencher) { fn $name(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
let x: &[i32] = &[$amount; $length]; let x: &[i32] = &[$amount; $length];
let mut result = [0i32; $amount]; let mut result = [0i32; $amount];
b.iter(|| { b.iter(|| {
@ -76,14 +76,14 @@ seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100);
#[bench] #[bench]
fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) { fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
let x: &[usize] = &[1; 100]; let x: &[usize] = &[1; 100];
b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10)) b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10))
} }
#[bench] #[bench]
fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) { fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
let x: &[usize] = &[1; 100]; let x: &[usize] = &[1; 100];
let mut buf = [0; 10]; let mut buf = [0; 10];
b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf)) b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf))
@ -93,7 +93,7 @@ macro_rules! sample_indices {
($name:ident, $fn:ident, $amount:expr, $length:expr) => { ($name:ident, $fn:ident, $amount:expr, $length:expr) => {
#[bench] #[bench]
fn $name(b: &mut Bencher) { fn $name(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
b.iter(|| index::$fn(&mut rng, $length, $amount)) b.iter(|| index::$fn(&mut rng, $length, $amount))
} }
}; };
@ -112,7 +112,7 @@ macro_rules! sample_indices_rand_weights {
($name:ident, $amount:expr, $length:expr) => { ($name:ident, $amount:expr, $length:expr) => {
#[bench] #[bench]
fn $name(b: &mut Bencher) { fn $name(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut rng = SmallRng::from_rng(thread_rng());
b.iter(|| { b.iter(|| {
index::sample_weighted(&mut rng, $length, |idx| (1 + (idx % 100)) as u32, $amount) index::sample_weighted(&mut rng, $length, |idx| (1 + (idx % 100)) as u32, $amount)
}) })

View File

@ -30,7 +30,7 @@ macro_rules! distr_int {
$group.throughput(Throughput::Bytes( $group.throughput(Throughput::Bytes(
size_of::<$ty>() as u64 * RAND_BENCH_N)); size_of::<$ty>() as u64 * RAND_BENCH_N));
$group.bench_function($fnn, |c| { $group.bench_function($fnn, |c| {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
c.iter(|| { c.iter(|| {
@ -50,7 +50,7 @@ macro_rules! distr_float {
$group.throughput(Throughput::Bytes( $group.throughput(Throughput::Bytes(
size_of::<$ty>() as u64 * RAND_BENCH_N)); size_of::<$ty>() as u64 * RAND_BENCH_N));
$group.bench_function($fnn, |c| { $group.bench_function($fnn, |c| {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
c.iter(|| { c.iter(|| {
@ -70,7 +70,7 @@ macro_rules! distr {
$group.throughput(Throughput::Bytes( $group.throughput(Throughput::Bytes(
size_of::<$ty>() as u64 * RAND_BENCH_N)); size_of::<$ty>() as u64 * RAND_BENCH_N));
$group.bench_function($fnn, |c| { $group.bench_function($fnn, |c| {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
c.iter(|| { c.iter(|| {
@ -90,7 +90,7 @@ macro_rules! distr_arr {
$group.throughput(Throughput::Bytes( $group.throughput(Throughput::Bytes(
size_of::<$ty>() as u64 * RAND_BENCH_N)); size_of::<$ty>() as u64 * RAND_BENCH_N));
$group.bench_function($fnn, |c| { $group.bench_function($fnn, |c| {
let mut rng = Pcg64Mcg::from_entropy(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = $distr; let distr = $distr;
c.iter(|| { c.iter(|| {
@ -127,8 +127,9 @@ fn bench(c: &mut Criterion<CyclesPerByte>) {
distr_float!(g, "log_normal", f64, LogNormal::new(-1.23, 4.56).unwrap()); distr_float!(g, "log_normal", f64, LogNormal::new(-1.23, 4.56).unwrap());
g.throughput(Throughput::Bytes(size_of::<f64>() as u64 * RAND_BENCH_N)); g.throughput(Throughput::Bytes(size_of::<f64>() as u64 * RAND_BENCH_N));
g.bench_function("iter", |c| { g.bench_function("iter", |c| {
let mut rng = Pcg64Mcg::from_entropy(); use core::f64::consts::{E, PI};
let distr = Normal::new(-2.71828, 3.14159).unwrap(); let mut rng = Pcg64Mcg::from_os_rng();
let distr = Normal::new(-E, PI).unwrap();
let mut iter = distr.sample_iter(&mut rng); let mut iter = distr.sample_iter(&mut rng);
c.iter(|| { c.iter(|| {
@ -176,9 +177,9 @@ fn bench(c: &mut Criterion<CyclesPerByte>) {
{ {
let mut g = c.benchmark_group("weighted"); let mut g = c.benchmark_group("weighted");
distr_int!(g, "weighted_i8", usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); distr_int!(g, "weighted_i8", usize, WeightedIndex::new([1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(g, "weighted_u32", usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); distr_int!(g, "weighted_u32", usize, WeightedIndex::new([1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(g, "weighted_f64", usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); distr_int!(g, "weighted_f64", usize, WeightedIndex::new([1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap());
distr_int!(g, "weighted_large_set", usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap()); distr_int!(g, "weighted_large_set", usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap());
distr_int!(g, "weighted_alias_method_i8", usize, WeightedAliasIndex::new(vec![1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); distr_int!(g, "weighted_alias_method_i8", usize, WeightedAliasIndex::new(vec![1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(g, "weighted_alias_method_u32", usize, WeightedAliasIndex::new(vec![1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); distr_int!(g, "weighted_alias_method_u32", usize, WeightedAliasIndex::new(vec![1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap());
@ -194,7 +195,7 @@ fn bench(c: &mut Criterion<CyclesPerByte>) {
sample_binomial!(g, "binomial_10", 10, 0.9); sample_binomial!(g, "binomial_10", 10, 0.9);
sample_binomial!(g, "binomial_100", 100, 0.99); sample_binomial!(g, "binomial_100", 100, 0.99);
sample_binomial!(g, "binomial_1000", 1000, 0.01); sample_binomial!(g, "binomial_1000", 1000, 0.01);
sample_binomial!(g, "binomial_1e12", 1000_000_000_000, 0.2); sample_binomial!(g, "binomial_1e12", 1_000_000_000_000, 0.2);
} }
{ {

View File

@ -23,8 +23,8 @@ const N_RESAMPLES: usize = 10_000;
macro_rules! sample { macro_rules! sample {
($R:ty, $T:ty, $U:ty, $g:expr) => { ($R:ty, $T:ty, $U:ty, $g:expr) => {
$g.bench_function(BenchmarkId::new(stringify!($R), "single"), |b| { $g.bench_function(BenchmarkId::new(stringify!($R), "single"), |b| {
let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let mut rng = <$R>::from_rng(thread_rng());
let x = rng.gen::<$U>(); let x = rng.random::<$U>();
let bits = (<$T>::BITS / 2); let bits = (<$T>::BITS / 2);
let mask = (1 as $U).wrapping_neg() >> bits; let mask = (1 as $U).wrapping_neg() >> bits;
let range = (x >> bits) * (x & mask); let range = (x >> bits) * (x & mask);
@ -35,8 +35,8 @@ macro_rules! sample {
}); });
$g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| { $g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| {
let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let mut rng = <$R>::from_rng(thread_rng());
let x = rng.gen::<$U>(); let x = rng.random::<$U>();
let bits = (<$T>::BITS / 2); let bits = (<$T>::BITS / 2);
let mask = (1 as $U).wrapping_neg() >> bits; let mask = (1 as $U).wrapping_neg() >> bits;
let range = (x >> bits) * (x & mask); let range = (x >> bits) * (x & mask);

View File

@ -27,11 +27,11 @@ const N_RESAMPLES: usize = 10_000;
macro_rules! single_random { macro_rules! single_random {
($R:ty, $T:ty, $g:expr) => { ($R:ty, $T:ty, $g:expr) => {
$g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| { $g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| {
let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let mut rng = <$R>::from_rng(thread_rng());
let (mut low, mut high); let (mut low, mut high);
loop { loop {
low = <$T>::from_bits(rng.gen()); low = <$T>::from_bits(rng.random());
high = <$T>::from_bits(rng.gen()); high = <$T>::from_bits(rng.random());
if (low < high) && (high - low).is_normal() { if (low < high) && (high - low).is_normal() {
break; break;
} }
@ -63,10 +63,10 @@ fn single_random(c: &mut Criterion) {
macro_rules! distr_random { macro_rules! distr_random {
($R:ty, $T:ty, $g:expr) => { ($R:ty, $T:ty, $g:expr) => {
$g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| { $g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| {
let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let mut rng = <$R>::from_rng(thread_rng());
let dist = loop { let dist = loop {
let low = <$T>::from_bits(rng.gen()); let low = <$T>::from_bits(rng.random());
let high = <$T>::from_bits(rng.gen()); let high = <$T>::from_bits(rng.random());
if let Ok(dist) = Uniform::<$T>::new_inclusive(low, high) { if let Ok(dist) = Uniform::<$T>::new_inclusive(low, high) {
break dist; break dist;
} }

View File

@ -36,7 +36,7 @@ Links:
`rand_chacha` is `no_std` compatible when disabling default features; the `std` `rand_chacha` is `no_std` compatible when disabling default features; the `std`
feature can be explicitly required to re-enable `std` support. Using `std` feature can be explicitly required to re-enable `std` support. Using `std`
allows detection of CPU features and thus better optimisation. Using `std` allows detection of CPU features and thus better optimisation. Using `std`
also enables `getrandom` functionality, such as `ChaCha20Rng::from_entropy()`. also enables `getrandom` functionality, such as `ChaCha20Rng::from_os_rng()`.
# License # License

View File

@ -14,9 +14,10 @@
use self::core::fmt; use self::core::fmt;
use crate::guts::ChaCha; use crate::guts::ChaCha;
use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng}; use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; use rand_core::{CryptoRng, RngCore, SeedableRng};
#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; #[cfg(feature = "serde1")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
// NB. this must remain consistent with some currently hard-coded numbers in this module // NB. this must remain consistent with some currently hard-coded numbers in this module
const BUF_BLOCKS: u8 = 4; const BUF_BLOCKS: u8 = 4;
@ -68,7 +69,7 @@ impl<T> fmt::Debug for Array64<T> {
} }
macro_rules! chacha_impl { macro_rules! chacha_impl {
($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident) => { ($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident,) => {
#[doc=$doc] #[doc=$doc]
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub struct $ChaChaXCore { pub struct $ChaChaXCore {
@ -85,6 +86,7 @@ macro_rules! chacha_impl {
impl BlockRngCore for $ChaChaXCore { impl BlockRngCore for $ChaChaXCore {
type Item = u32; type Item = u32;
type Results = Array64<u32>; type Results = Array64<u32>;
#[inline] #[inline]
fn generate(&mut self, r: &mut Self::Results) { fn generate(&mut self, r: &mut Self::Results) {
self.state.refill4($rounds, &mut r.0); self.state.refill4($rounds, &mut r.0);
@ -93,9 +95,12 @@ macro_rules! chacha_impl {
impl SeedableRng for $ChaChaXCore { impl SeedableRng for $ChaChaXCore {
type Seed = [u8; 32]; type Seed = [u8; 32];
#[inline] #[inline]
fn from_seed(seed: Self::Seed) -> Self { fn from_seed(seed: Self::Seed) -> Self {
$ChaChaXCore { state: ChaCha::new(&seed, &[0u8; 8]) } $ChaChaXCore {
state: ChaCha::new(&seed, &[0u8; 8]),
}
} }
} }
@ -146,6 +151,7 @@ macro_rules! chacha_impl {
impl SeedableRng for $ChaChaXRng { impl SeedableRng for $ChaChaXRng {
type Seed = [u8; 32]; type Seed = [u8; 32];
#[inline] #[inline]
fn from_seed(seed: Self::Seed) -> Self { fn from_seed(seed: Self::Seed) -> Self {
let core = $ChaChaXCore::from_seed(seed); let core = $ChaChaXCore::from_seed(seed);
@ -160,18 +166,16 @@ macro_rules! chacha_impl {
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
self.rng.next_u32() self.rng.next_u32()
} }
#[inline] #[inline]
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
self.rng.next_u64() self.rng.next_u64()
} }
#[inline] #[inline]
fn fill_bytes(&mut self, bytes: &mut [u8]) { fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.rng.fill_bytes(bytes) self.rng.fill_bytes(bytes)
} }
#[inline]
fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> {
self.rng.try_fill_bytes(bytes)
}
} }
impl $ChaChaXRng { impl $ChaChaXRng {
@ -209,11 +213,9 @@ macro_rules! chacha_impl {
#[inline] #[inline]
pub fn set_word_pos(&mut self, word_offset: u128) { pub fn set_word_pos(&mut self, word_offset: u128) {
let block = (word_offset / u128::from(BLOCK_WORDS)) as u64; let block = (word_offset / u128::from(BLOCK_WORDS)) as u64;
self.rng.core.state.set_block_pos(block);
self.rng self.rng
.core .generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
.state
.set_block_pos(block);
self.rng.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
} }
/// Set the stream number. /// Set the stream number.
@ -229,10 +231,7 @@ macro_rules! chacha_impl {
/// indirectly via `set_word_pos`), but this is not directly supported. /// indirectly via `set_word_pos`), but this is not directly supported.
#[inline] #[inline]
pub fn set_stream(&mut self, stream: u64) { pub fn set_stream(&mut self, stream: u64) {
self.rng self.rng.core.state.set_nonce(stream);
.core
.state
.set_nonce(stream);
if self.rng.index() != 64 { if self.rng.index() != 64 {
let wp = self.get_word_pos(); let wp = self.get_word_pos();
self.set_word_pos(wp); self.set_word_pos(wp);
@ -242,24 +241,20 @@ macro_rules! chacha_impl {
/// Get the stream number. /// Get the stream number.
#[inline] #[inline]
pub fn get_stream(&self) -> u64 { pub fn get_stream(&self) -> u64 {
self.rng self.rng.core.state.get_nonce()
.core
.state
.get_nonce()
} }
/// Get the seed. /// Get the seed.
#[inline] #[inline]
pub fn get_seed(&self) -> [u8; 32] { pub fn get_seed(&self) -> [u8; 32] {
self.rng self.rng.core.state.get_seed()
.core
.state
.get_seed()
} }
} }
impl CryptoRng for $ChaChaXRng {} impl CryptoRng for $ChaChaXRng {}
rand_core::impl_try_crypto_rng_from_crypto_rng!($ChaChaXRng);
impl From<$ChaChaXCore> for $ChaChaXRng { impl From<$ChaChaXCore> for $ChaChaXRng {
fn from(core: $ChaChaXCore) -> Self { fn from(core: $ChaChaXCore) -> Self {
$ChaChaXRng { $ChaChaXRng {
@ -286,22 +281,20 @@ macro_rules! chacha_impl {
} }
#[cfg(feature = "serde1")] #[cfg(feature = "serde1")]
impl<'de> Deserialize<'de> for $ChaChaXRng { impl<'de> Deserialize<'de> for $ChaChaXRng {
fn deserialize<D>(d: D) -> Result<Self, D::Error> where D: Deserializer<'de> { fn deserialize<D>(d: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
$abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x)) $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
} }
} }
mod $abst { mod $abst {
#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize}; #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
// The abstract state of a ChaCha stream, independent of implementation choices. The // The abstract state of a ChaCha stream, independent of implementation choices. The
// comparison and serialization of this object is considered a semver-covered part of // comparison and serialization of this object is considered a semver-covered part of
// the API. // the API.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr( #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
feature = "serde1",
derive(Serialize, Deserialize),
)]
pub(crate) struct $ChaChaXRng { pub(crate) struct $ChaChaXRng {
seed: [u8; 32], seed: [u8; 32],
stream: u64, stream: u64,
@ -331,18 +324,36 @@ macro_rules! chacha_impl {
} }
} }
} }
} };
} }
chacha_impl!(ChaCha20Core, ChaCha20Rng, 10, "ChaCha with 20 rounds", abstract20); chacha_impl!(
chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds", abstract12); ChaCha20Core,
chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds", abstract8); ChaCha20Rng,
10,
"ChaCha with 20 rounds",
abstract20,
);
chacha_impl!(
ChaCha12Core,
ChaCha12Rng,
6,
"ChaCha with 12 rounds",
abstract12,
);
chacha_impl!(
ChaCha8Core,
ChaCha8Rng,
4,
"ChaCha with 8 rounds",
abstract8,
);
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
#[cfg(feature = "serde1")] use super::{ChaCha20Rng, ChaCha12Rng, ChaCha8Rng}; #[cfg(feature = "serde1")] use super::{ChaCha12Rng, ChaCha20Rng, ChaCha8Rng};
type ChaChaRng = super::ChaCha20Rng; type ChaChaRng = super::ChaCha20Rng;
@ -350,8 +361,8 @@ mod test {
#[test] #[test]
fn test_chacha_serde_roundtrip() { fn test_chacha_serde_roundtrip() {
let seed = [ let seed = [
1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0, 0, 0, 1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0,
0, 2, 92, 0, 0, 0, 2, 92,
]; ];
let mut rng1 = ChaCha20Rng::from_seed(seed); let mut rng1 = ChaCha20Rng::from_seed(seed);
let mut rng2 = ChaCha12Rng::from_seed(seed); let mut rng2 = ChaCha12Rng::from_seed(seed);
@ -388,7 +399,7 @@ mod test {
#[test] #[test]
fn test_chacha_serde_format_stability() { fn test_chacha_serde_format_stability() {
let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#; let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#;
let r: ChaChaRng = serde_json::from_str(&j).unwrap(); let r: ChaChaRng = serde_json::from_str(j).unwrap();
let j1 = serde_json::to_string(&r).unwrap(); let j1 = serde_json::to_string(&r).unwrap();
assert_eq!(j, j1); assert_eq!(j, j1);
} }
@ -402,7 +413,7 @@ mod test {
let mut rng1 = ChaChaRng::from_seed(seed); let mut rng1 = ChaChaRng::from_seed(seed);
assert_eq!(rng1.next_u32(), 137206642); assert_eq!(rng1.next_u32(), 137206642);
let mut rng2 = ChaChaRng::from_rng(rng1).unwrap(); let mut rng2 = ChaChaRng::from_rng(&mut rng1);
assert_eq!(rng2.next_u32(), 1325750369); assert_eq!(rng2.next_u32(), 1325750369);
} }
@ -598,7 +609,7 @@ mod test {
#[test] #[test]
fn test_chacha_word_pos_wrap_exact() { fn test_chacha_word_pos_wrap_exact() {
use super::{BUF_BLOCKS, BLOCK_WORDS}; use super::{BLOCK_WORDS, BUF_BLOCKS};
let mut rng = ChaChaRng::from_seed(Default::default()); let mut rng = ChaChaRng::from_seed(Default::default());
// refilling the buffer in set_word_pos will wrap the block counter to 0 // refilling the buffer in set_word_pos will wrap the block counter to 0
let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS); let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS);

View File

@ -0,0 +1,91 @@
#[cfg(feature = "alloc")] use alloc::boxed::Box;
use crate::{CryptoRng, RngCore, TryCryptoRng, TryRngCore};
impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
R::next_u32(self)
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
R::next_u64(self)
}
#[inline(always)]
fn fill_bytes(&mut self, dst: &mut [u8]) {
R::fill_bytes(self, dst)
}
}
impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
impl<'a, R: TryRngCore + ?Sized> TryRngCore for &'a mut R {
type Error = R::Error;
#[inline(always)]
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
R::try_next_u32(self)
}
#[inline(always)]
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
R::try_next_u64(self)
}
#[inline(always)]
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
R::try_fill_bytes(self, dst)
}
}
impl<'a, R: TryCryptoRng + ?Sized> TryCryptoRng for &'a mut R {}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: RngCore + ?Sized> RngCore for Box<R> {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
R::next_u32(self)
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
R::next_u64(self)
}
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
R::fill_bytes(self, dest)
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: TryRngCore + ?Sized> TryRngCore for Box<R> {
type Error = R::Error;
#[inline(always)]
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
R::try_next_u32(self)
}
#[inline(always)]
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
R::try_next_u64(self)
}
#[inline(always)]
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
R::try_fill_bytes(self, dst)
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: TryCryptoRng + ?Sized> TryCryptoRng for Box<R> {}

View File

@ -54,10 +54,9 @@
//! [`fill_bytes`]: RngCore::fill_bytes //! [`fill_bytes`]: RngCore::fill_bytes
use crate::impls::{fill_via_u32_chunks, fill_via_u64_chunks}; use crate::impls::{fill_via_u32_chunks, fill_via_u64_chunks};
use crate::{Error, CryptoRng, RngCore, SeedableRng}; use crate::{CryptoRng, RngCore, SeedableRng, TryRngCore};
use core::fmt; use core::fmt;
#[cfg(feature = "serde1")] #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize};
/// A trait for RNGs which do not generate random numbers individually, but in /// A trait for RNGs which do not generate random numbers individually, but in
/// blocks (typically `[u32; N]`). This technique is commonly used by /// blocks (typically `[u32; N]`). This technique is commonly used by
@ -80,7 +79,7 @@ pub trait BlockRngCore {
/// supposed to be cryptographically secure. /// supposed to be cryptographically secure.
/// ///
/// See [`CryptoRng`] docs for more information. /// See [`CryptoRng`] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { } pub trait CryptoBlockRng: BlockRngCore {}
/// A wrapper type implementing [`RngCore`] for some type implementing /// A wrapper type implementing [`RngCore`] for some type implementing
/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement /// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement
@ -97,16 +96,15 @@ pub trait CryptoBlockRng: BlockRngCore { }
/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods /// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods
/// reading values from the results buffer, as well as /// reading values from the results buffer, as well as
/// calling [`BlockRngCore::generate`] directly on the output array when /// calling [`BlockRngCore::generate`] directly on the output array when
/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods /// [`fill_bytes`] is called on a large array. These methods also handle
/// also handle the bookkeeping of when to generate a new batch of values. /// the bookkeeping of when to generate a new batch of values.
/// ///
/// No whole generated `u32` values are thrown away and all values are consumed /// No whole generated `u32` values are thrown away and all values are consumed
/// in-order. [`next_u32`] simply takes the next available `u32` value. /// in-order. [`next_u32`] simply takes the next available `u32` value.
/// [`next_u64`] is implemented by combining two `u32` values, least /// [`next_u64`] is implemented by combining two `u32` values, least
/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole /// significant first. [`fill_bytes`] consume a whole number of `u32` values,
/// number of `u32` values, converting each `u32` to a byte slice in /// converting each `u32` to a byte slice in little-endian order. If the requested byte
/// little-endian order. If the requested byte length is not a multiple of 4, /// length is not a multiple of 4, some bytes will be discarded.
/// some bytes will be discarded.
/// ///
/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is /// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is
/// no direct support for other buffer types. /// no direct support for other buffer types.
@ -116,7 +114,6 @@ pub trait CryptoBlockRng: BlockRngCore { }
/// [`next_u32`]: RngCore::next_u32 /// [`next_u32`]: RngCore::next_u32
/// [`next_u64`]: RngCore::next_u64 /// [`next_u64`]: RngCore::next_u64
/// [`fill_bytes`]: RngCore::fill_bytes /// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
#[derive(Clone)] #[derive(Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
@ -227,19 +224,15 @@ impl<R: BlockRngCore<Item = u32>> RngCore for BlockRng<R> {
if self.index >= self.results.as_ref().len() { if self.index >= self.results.as_ref().len() {
self.generate_and_set(0); self.generate_and_set(0);
} }
let (consumed_u32, filled_u8) = let (consumed_u32, filled_u8) = fill_via_u32_chunks(
fill_via_u32_chunks(&mut self.results.as_mut()[self.index..], &mut dest[read_len..]); &mut self.results.as_mut()[self.index..],
&mut dest[read_len..],
);
self.index += consumed_u32; self.index += consumed_u32;
read_len += filled_u8; read_len += filled_u8;
} }
} }
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
} }
impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> { impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
@ -256,8 +249,13 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
} }
#[inline(always)] #[inline(always)]
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { fn from_rng(rng: impl RngCore) -> Self {
Ok(Self::new(R::from_rng(rng)?)) Self::new(R::from_rng(rng))
}
#[inline(always)]
fn try_from_rng<S: TryRngCore>(rng: S) -> Result<Self, S::Error> {
R::try_from_rng(rng).map(Self::new)
} }
} }
@ -277,14 +275,12 @@ impl<R: CryptoBlockRng + BlockRngCore<Item = u32>> CryptoRng for BlockRng<R> {}
/// then the other half is then consumed, however both [`next_u64`] and /// then the other half is then consumed, however both [`next_u64`] and
/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called. /// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called.
/// ///
/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64` /// [`fill_bytes`] `] consume a whole number of `u64` values. If the requested length
/// values. If the requested length is not a multiple of 8, some bytes will be /// is not a multiple of 8, some bytes will be discarded.
/// discarded.
/// ///
/// [`next_u32`]: RngCore::next_u32 /// [`next_u32`]: RngCore::next_u32
/// [`next_u64`]: RngCore::next_u64 /// [`next_u64`]: RngCore::next_u64
/// [`fill_bytes`]: RngCore::fill_bytes /// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
#[derive(Clone)] #[derive(Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct BlockRng64<R: BlockRngCore + ?Sized> { pub struct BlockRng64<R: BlockRngCore + ?Sized> {
@ -402,12 +398,6 @@ impl<R: BlockRngCore<Item = u64>> RngCore for BlockRng64<R> {
read_len += filled_u8; read_len += filled_u8;
} }
} }
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
} }
impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> { impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
@ -424,8 +414,13 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
} }
#[inline(always)] #[inline(always)]
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { fn from_rng(rng: impl RngCore) -> Self {
Ok(Self::new(R::from_rng(rng)?)) Self::new(R::from_rng(rng))
}
#[inline(always)]
fn try_from_rng<S: TryRngCore>(rng: S) -> Result<Self, S::Error> {
R::try_from_rng(rng).map(Self::new)
} }
} }
@ -433,8 +428,8 @@ impl<R: CryptoBlockRng + BlockRngCore<Item = u64>> CryptoRng for BlockRng64<R> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{SeedableRng, RngCore};
use crate::block::{BlockRng, BlockRng64, BlockRngCore}; use crate::block::{BlockRng, BlockRng64, BlockRngCore};
use crate::{RngCore, SeedableRng};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct DummyRng { struct DummyRng {
@ -443,7 +438,6 @@ mod test {
impl BlockRngCore for DummyRng { impl BlockRngCore for DummyRng {
type Item = u32; type Item = u32;
type Results = [u32; 16]; type Results = [u32; 16];
fn generate(&mut self, results: &mut Self::Results) { fn generate(&mut self, results: &mut Self::Results) {
@ -458,7 +452,9 @@ mod test {
type Seed = [u8; 4]; type Seed = [u8; 4];
fn from_seed(seed: Self::Seed) -> Self { fn from_seed(seed: Self::Seed) -> Self {
DummyRng { counter: u32::from_le_bytes(seed) } DummyRng {
counter: u32::from_le_bytes(seed),
}
} }
} }
@ -493,7 +489,6 @@ mod test {
impl BlockRngCore for DummyRng64 { impl BlockRngCore for DummyRng64 {
type Item = u64; type Item = u64;
type Results = [u64; 8]; type Results = [u64; 8];
fn generate(&mut self, results: &mut Self::Results) { fn generate(&mut self, results: &mut Self::Results) {
@ -508,7 +503,9 @@ mod test {
type Seed = [u8; 8]; type Seed = [u8; 8];
fn from_seed(seed: Self::Seed) -> Self { fn from_seed(seed: Self::Seed) -> Self {
DummyRng64 { counter: u64::from_le_bytes(seed) } DummyRng64 {
counter: u64::from_le_bytes(seed),
}
} }
} }

View File

@ -1,226 +0,0 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Error types
use core::fmt;
use core::num::NonZeroU32;
#[cfg(feature = "std")] use std::boxed::Box;
/// Error type of random number generators
///
/// In order to be compatible with `std` and `no_std`, this type has two
/// possible implementations: with `std` a boxed `Error` trait object is stored,
/// while with `no_std` we merely store an error code.
pub struct Error {
#[cfg(feature = "std")]
inner: Box<dyn std::error::Error + Send + Sync + 'static>,
#[cfg(not(feature = "std"))]
code: NonZeroU32,
}
impl Error {
/// Codes at or above this point can be used by users to define their own
/// custom errors.
///
/// This has a fixed value of `(1 << 31) + (1 << 30) = 0xC000_0000`,
/// therefore the number of values available for custom codes is `1 << 30`.
///
/// This is identical to [`getrandom::Error::CUSTOM_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.CUSTOM_START).
pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
/// Codes below this point represent OS Errors (i.e. positive i32 values).
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
/// reserved for use by the `rand` and `getrandom` crates.
///
/// This is identical to [`getrandom::Error::INTERNAL_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.INTERNAL_START).
pub const INTERNAL_START: u32 = 1 << 31;
/// Construct from any type supporting `std::error::Error`
///
/// Available only when configured with `std`.
///
/// See also `From<NonZeroU32>`, which is available with and without `std`.
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[inline]
pub fn new<E>(err: E) -> Self
where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>> {
Error { inner: err.into() }
}
/// Reference the inner error (`std` only)
///
/// When configured with `std`, this is a trivial operation and never
/// panics. Without `std`, this method is simply unavailable.
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[inline]
pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
&*self.inner
}
/// Unwrap the inner error (`std` only)
///
/// When configured with `std`, this is a trivial operation and never
/// panics. Without `std`, this method is simply unavailable.
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[inline]
pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> {
self.inner
}
/// Extract the raw OS error code (if this error came from the OS)
///
/// This method is identical to `std::io::Error::raw_os_error()`, except
/// that it works in `no_std` contexts. If this method returns `None`, the
/// error value can still be formatted via the `Display` implementation.
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
#[cfg(feature = "std")]
{
if let Some(e) = self.inner.downcast_ref::<std::io::Error>() {
return e.raw_os_error();
}
}
match self.code() {
Some(code) if u32::from(code) < Self::INTERNAL_START => Some(u32::from(code) as i32),
_ => None,
}
}
/// Retrieve the error code, if any.
///
/// If this `Error` was constructed via `From<NonZeroU32>`, then this method
/// will return this `NonZeroU32` code (for `no_std` this is always the
/// case). Otherwise, this method will return `None`.
#[inline]
pub fn code(&self) -> Option<NonZeroU32> {
#[cfg(feature = "std")]
{
self.inner.downcast_ref::<ErrorCode>().map(|c| c.0)
}
#[cfg(not(feature = "std"))]
{
Some(self.code)
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(feature = "std")]
{
write!(f, "Error {{ inner: {:?} }}", self.inner)
}
#[cfg(all(feature = "getrandom", not(feature = "std")))]
{
getrandom::Error::from(self.code).fmt(f)
}
#[cfg(not(any(feature = "getrandom", feature = "std")))]
{
write!(f, "Error {{ code: {} }}", self.code)
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(feature = "std")]
{
write!(f, "{}", self.inner)
}
#[cfg(all(feature = "getrandom", not(feature = "std")))]
{
getrandom::Error::from(self.code).fmt(f)
}
#[cfg(not(any(feature = "getrandom", feature = "std")))]
{
write!(f, "error code {}", self.code)
}
}
}
impl From<NonZeroU32> for Error {
#[inline]
fn from(code: NonZeroU32) -> Self {
#[cfg(feature = "std")]
{
Error {
inner: Box::new(ErrorCode(code)),
}
}
#[cfg(not(feature = "std"))]
{
Error { code }
}
}
}
#[cfg(feature = "getrandom")]
impl From<getrandom::Error> for Error {
#[inline]
fn from(error: getrandom::Error) -> Self {
#[cfg(feature = "std")]
{
Error {
inner: Box::new(error),
}
}
#[cfg(not(feature = "std"))]
{
Error { code: error.code() }
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.source()
}
}
#[cfg(feature = "std")]
impl From<Error> for std::io::Error {
#[inline]
fn from(error: Error) -> Self {
if let Some(code) = error.raw_os_error() {
std::io::Error::from_raw_os_error(code)
} else {
std::io::Error::new(std::io::ErrorKind::Other, error)
}
}
}
#[cfg(feature = "std")]
#[derive(Debug, Copy, Clone)]
struct ErrorCode(NonZeroU32);
#[cfg(feature = "std")]
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "error code {}", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ErrorCode {}
#[cfg(test)]
mod test {
#[cfg(feature = "getrandom")]
#[test]
fn test_error_codes() {
// Make sure the values are the same as in `getrandom`.
assert_eq!(super::Error::CUSTOM_START, getrandom::Error::CUSTOM_START);
assert_eq!(super::Error::INTERNAL_START, getrandom::Error::INTERNAL_START);
}
}

View File

@ -74,7 +74,7 @@ impl Observable for u64 {
/// unaltered. /// unaltered.
fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usize) { fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usize) {
let size = core::mem::size_of::<T>(); let size = core::mem::size_of::<T>();
let byte_len = min(src.len() * size, dest.len()); let byte_len = min(core::mem::size_of_val(src), dest.len());
let num_chunks = (byte_len + size - 1) / size; let num_chunks = (byte_len + size - 1) / size;
// Byte-swap for portability of results. This must happen before copying // Byte-swap for portability of results. This must happen before copying
@ -160,6 +160,56 @@ pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
u64::from_le_bytes(buf) u64::from_le_bytes(buf)
} }
/// Implement [`TryRngCore`] for a type implementing [`RngCore`].
///
/// Ideally, `rand_core` would define blanket impls for this, but they conflict with blanket impls
/// for `&mut R` and `Box<R>`, so until specialziation is stabilized, implementer crates
/// have to implement `TryRngCore` directly.
#[macro_export]
macro_rules! impl_try_rng_from_rng_core {
($t:ty) => {
impl $crate::TryRngCore for $t {
type Error = core::convert::Infallible;
#[inline]
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok($crate::RngCore::next_u32(self))
}
#[inline]
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
Ok($crate::RngCore::next_u64(self))
}
#[inline]
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
$crate::RngCore::fill_bytes(self, dst);
Ok(())
}
}
};
}
/// Implement [`TryCryptoRng`] and [`TryRngCore`] for a type implementing [`CryptoRng`].
///
/// Ideally, `rand_core` would define blanket impls for this, but they conflict with blanket impls
/// for `&mut R` and `Box<R>`, so until specialziation is stabilized, implementer crates
/// have to implement `TryRngCore` and `TryCryptoRng` directly.
#[macro_export]
macro_rules! impl_try_crypto_rng_from_crypto_rng {
($t:ty) => {
$crate::impl_try_rng_from_rng_core!($t);
impl $crate::TryCryptoRng for $t {}
/// Check at compile time that `$t` implements `CryptoRng`
const _: () = {
const fn check_crypto_rng_impl<T: $crate::CryptoRng>() {}
check_crypto_rng_impl::<$t>();
};
};
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -19,9 +19,6 @@
//! [`SeedableRng`] is an extension trait for construction from fixed seeds and //! [`SeedableRng`] is an extension trait for construction from fixed seeds and
//! other random number generators. //! other random number generators.
//! //!
//! [`Error`] is provided for error-handling. It is safe to use in `no_std`
//! environments.
//!
//! The [`impls`] and [`le`] sub-modules include a few small functions to assist //! The [`impls`] and [`le`] sub-modules include a few small functions to assist
//! implementation of [`RngCore`]. //! implementation of [`RngCore`].
//! //!
@ -40,18 +37,18 @@
#[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "alloc")] extern crate alloc;
#[cfg(feature = "std")] extern crate std; #[cfg(feature = "std")] extern crate std;
#[cfg(feature = "alloc")] use alloc::boxed::Box;
pub use error::Error;
#[cfg(feature = "getrandom")] pub use os::OsRng;
use core::fmt;
mod blanket_impls;
pub mod block; pub mod block;
mod error;
pub mod impls; pub mod impls;
pub mod le; pub mod le;
#[cfg(feature = "getrandom")] mod os; #[cfg(feature = "getrandom")] mod os;
#[cfg(feature = "getrandom")] pub use getrandom;
#[cfg(feature = "getrandom")] pub use os::OsRng;
/// The core of a random number generator. /// The core of a random number generator.
/// ///
@ -68,11 +65,6 @@ pub mod le;
/// [`next_u32`] and [`next_u64`] methods, implementations may discard some /// [`next_u32`] and [`next_u64`] methods, implementations may discard some
/// random bits for efficiency. /// random bits for efficiency.
/// ///
/// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error
/// handling; it is not deemed sufficiently useful to add equivalents for
/// [`next_u32`] or [`next_u64`] since the latter methods are almost always used
/// with algorithmic generators (PRNGs), which are normally infallible.
///
/// Implementers should produce bits uniformly. Pathological RNGs (e.g. always /// Implementers should produce bits uniformly. Pathological RNGs (e.g. always
/// returning the same value, or never setting certain bits) can break rejection /// returning the same value, or never setting certain bits) can break rejection
/// sampling used by random distributions, and also break other RNGs when /// sampling used by random distributions, and also break other RNGs when
@ -87,6 +79,10 @@ pub mod le;
/// in this trait directly, then use the helper functions from the /// in this trait directly, then use the helper functions from the
/// [`impls`] module to implement the other methods. /// [`impls`] module to implement the other methods.
/// ///
/// Implementors of [`RngCore`] SHOULD also implement the [`TryRngCore`]
/// trait with the `Error` associated type being equal to [`Infallible`].
/// It can be done using the [`impl_try_rng_from_rng_core!`] macro.
///
/// It is recommended that implementations also implement: /// It is recommended that implementations also implement:
/// ///
/// - `Debug` with a custom implementation which *does not* print any internal /// - `Debug` with a custom implementation which *does not* print any internal
@ -107,7 +103,7 @@ pub mod le;
/// ///
/// ``` /// ```
/// #![allow(dead_code)] /// #![allow(dead_code)]
/// use rand_core::{RngCore, Error, impls}; /// use rand_core::{RngCore, impls};
/// ///
/// struct CountingRng(u64); /// struct CountingRng(u64);
/// ///
@ -121,21 +117,19 @@ pub mod le;
/// self.0 /// self.0
/// } /// }
/// ///
/// fn fill_bytes(&mut self, dest: &mut [u8]) { /// fn fill_bytes(&mut self, dst: &mut [u8]) {
/// impls::fill_bytes_via_next(self, dest) /// impls::fill_bytes_via_next(self, dst)
/// }
///
/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
/// Ok(self.fill_bytes(dest))
/// } /// }
/// } /// }
///
/// rand_core::impl_try_rng_from_rng_core!(CountingRng);
/// ``` /// ```
/// ///
/// [`rand`]: https://docs.rs/rand /// [`rand`]: https://docs.rs/rand
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
/// [`fill_bytes`]: RngCore::fill_bytes /// [`fill_bytes`]: RngCore::fill_bytes
/// [`next_u32`]: RngCore::next_u32 /// [`next_u32`]: RngCore::next_u32
/// [`next_u64`]: RngCore::next_u64 /// [`next_u64`]: RngCore::next_u64
/// [`Infallible`]: core::convert::Infallible
pub trait RngCore { pub trait RngCore {
/// Return the next random `u32`. /// Return the next random `u32`.
/// ///
@ -155,42 +149,22 @@ pub trait RngCore {
/// ///
/// RNGs must implement at least one method from this trait directly. In /// RNGs must implement at least one method from this trait directly. In
/// the case this method is not implemented directly, it can be implemented /// the case this method is not implemented directly, it can be implemented
/// via [`impls::fill_bytes_via_next`] or /// via [`impls::fill_bytes_via_next`].
/// via [`RngCore::try_fill_bytes`]; if this generator can
/// fail the implementation must choose how best to handle errors here
/// (e.g. panic with a descriptive message or log a warning and retry a few
/// times).
/// ///
/// This method should guarantee that `dest` is entirely filled /// This method should guarantee that `dest` is entirely filled
/// with new data, and may panic if this is impossible /// with new data, and may panic if this is impossible
/// (e.g. reading past the end of a file that is being used as the /// (e.g. reading past the end of a file that is being used as the
/// source of randomness). /// source of randomness).
fn fill_bytes(&mut self, dest: &mut [u8]); fn fill_bytes(&mut self, dst: &mut [u8]);
/// Fill `dest` entirely with random data.
///
/// This is the only method which allows an RNG to report errors while
/// generating random data thus making this the primary method implemented
/// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used
/// directly to generate keys and to seed (infallible) PRNGs.
///
/// Other than error handling, this method is identical to [`RngCore::fill_bytes`];
/// thus this may be implemented using `Ok(self.fill_bytes(dest))` or
/// `fill_bytes` may be implemented with
/// `self.try_fill_bytes(dest).unwrap()` or more specific error handling.
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>;
/// Convert an [`RngCore`] to a [`RngReadAdapter`].
#[cfg(feature = "std")]
fn read_adapter(&mut self) -> RngReadAdapter<'_, Self>
where Self: Sized {
RngReadAdapter { inner: self }
}
} }
/// A marker trait used to indicate that an [`RngCore`] implementation is /// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to be cryptographically secure. /// supposed to be cryptographically secure.
/// ///
/// Implementors of [`CryptoRng`] SHOULD also implement the [`TryCryptoRng`]
/// trait with the `Error` associated type being equal to [`Infallible`].
/// It can be done using the [`impl_try_crypto_rng_from_crypto_rng!`] macro.
///
/// *Cryptographically secure generators*, also known as *CSPRNGs*, should /// *Cryptographically secure generators*, also known as *CSPRNGs*, should
/// satisfy an additional properties over other generators: given the first /// satisfy an additional properties over other generators: given the first
/// *k* bits of an algorithm's output /// *k* bits of an algorithm's output
@ -210,8 +184,74 @@ pub trait RngCore {
/// weaknesses such as seeding from a weak entropy source or leaking state. /// weaknesses such as seeding from a weak entropy source or leaking state.
/// ///
/// [`BlockRngCore`]: block::BlockRngCore /// [`BlockRngCore`]: block::BlockRngCore
/// [`Infallible`]: core::convert::Infallible
pub trait CryptoRng: RngCore {} pub trait CryptoRng: RngCore {}
/// A potentially fallible version of [`RngCore`].
///
/// This trait is primarily used for IO-based generators such as [`OsRng`].
///
/// Most of higher-level generic code in the `rand` crate is built on top
/// of the the [`RngCore`] trait. Users can transform a fallible RNG
/// (i.e. [`TryRngCore`] implementor) into an "infallible" (but potentially
/// panicking) RNG (i.e. [`RngCore`] implementor) using the [`UnwrapErr`] wrapper.
///
/// [`RngCore`] implementors also usually implement [`TryRngCore`] with the `Error`
/// associated type being equal to [`Infallible`][core::convert::Infallible].
/// In other words, users can use [`TryRngCore`] to generalize over fallible and
/// infallible RNGs.
pub trait TryRngCore {
/// The type returned in the event of a RNG error.
type Error: fmt::Debug + fmt::Display;
/// Return the next random `u32`.
fn try_next_u32(&mut self) -> Result<u32, Self::Error>;
/// Return the next random `u64`.
fn try_next_u64(&mut self) -> Result<u64, Self::Error>;
/// Fill `dest` entirely with random data.
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error>;
/// Wrap RNG with the [`UnwrapErr`] wrapper.
fn unwrap_err(self) -> UnwrapErr<Self>
where Self: Sized {
UnwrapErr(self)
}
/// Convert an [`RngCore`] to a [`RngReadAdapter`].
#[cfg(feature = "std")]
fn read_adapter(&mut self) -> RngReadAdapter<'_, Self>
where Self: Sized {
RngReadAdapter { inner: self }
}
}
/// A marker trait used to indicate that a [`TryRngCore`] implementation is
/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`] docs for more information about cryptographically secure generators.
pub trait TryCryptoRng: TryRngCore {}
/// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`]
/// by panicking on potential errors.
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
pub struct UnwrapErr<R: TryRngCore>(pub R);
impl<R: TryRngCore> RngCore for UnwrapErr<R> {
fn next_u32(&mut self) -> u32 {
self.0.try_next_u32().unwrap()
}
fn next_u64(&mut self) -> u64 {
self.0.try_next_u64().unwrap()
}
fn fill_bytes(&mut self, dst: &mut [u8]) {
self.0.try_fill_bytes(dst).unwrap()
}
}
impl<R: TryCryptoRng> CryptoRng for UnwrapErr<R> {}
/// A random number generator that can be explicitly seeded. /// A random number generator that can be explicitly seeded.
/// ///
/// This trait encapsulates the low-level functionality common to all /// This trait encapsulates the low-level functionality common to all
@ -339,7 +379,7 @@ pub trait SeedableRng: Sized {
Self::from_seed(seed) Self::from_seed(seed)
} }
/// Create a new PRNG seeded from another `Rng`. /// Create a new PRNG seeded from an infallible `Rng`.
/// ///
/// This may be useful when needing to rapidly seed many PRNGs from a master /// This may be useful when needing to rapidly seed many PRNGs from a master
/// PRNG, and to allow forking of PRNGs. It may be considered deterministic. /// PRNG, and to allow forking of PRNGs. It may be considered deterministic.
@ -363,7 +403,16 @@ pub trait SeedableRng: Sized {
/// (in prior versions this was not required). /// (in prior versions this was not required).
/// ///
/// [`rand`]: https://docs.rs/rand /// [`rand`]: https://docs.rs/rand
fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { fn from_rng(mut rng: impl RngCore) -> Self {
let mut seed = Self::Seed::default();
rng.fill_bytes(seed.as_mut());
Self::from_seed(seed)
}
/// Create a new PRNG seeded from a potentially fallible `Rng`.
///
/// See [`from_rng`][SeedableRng::from_rng] docs for more infromation.
fn try_from_rng<R: TryRngCore>(mut rng: R) -> Result<Self, R::Error> {
let mut seed = Self::Seed::default(); let mut seed = Self::Seed::default();
rng.try_fill_bytes(seed.as_mut())?; rng.try_fill_bytes(seed.as_mut())?;
Ok(Self::from_seed(seed)) Ok(Self::from_seed(seed))
@ -374,6 +423,9 @@ pub trait SeedableRng: Sized {
/// This method is the recommended way to construct non-deterministic PRNGs /// This method is the recommended way to construct non-deterministic PRNGs
/// since it is convenient and secure. /// since it is convenient and secure.
/// ///
/// Note that this method may panic on (extremely unlikely) [`getrandom`] errors.
/// If it's not desirable, use the [`try_from_os_rng`] method instead.
///
/// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an /// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an
/// issue, one may prefer to seed from a local PRNG, e.g. /// issue, one may prefer to seed from a local PRNG, e.g.
/// `from_rng(thread_rng()).unwrap()`. /// `from_rng(thread_rng()).unwrap()`.
@ -383,66 +435,32 @@ pub trait SeedableRng: Sized {
/// If [`getrandom`] is unable to provide secure entropy this method will panic. /// If [`getrandom`] is unable to provide secure entropy this method will panic.
/// ///
/// [`getrandom`]: https://docs.rs/getrandom /// [`getrandom`]: https://docs.rs/getrandom
/// [`try_from_os_rng`]: SeedableRng::try_from_os_rng
#[cfg(feature = "getrandom")] #[cfg(feature = "getrandom")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[track_caller] #[track_caller]
fn from_entropy() -> Self { fn from_os_rng() -> Self {
let mut seed = Self::Seed::default(); match Self::try_from_os_rng() {
if let Err(err) = getrandom::getrandom(seed.as_mut()) { Ok(res) => res,
panic!("from_entropy failed: {}", err); Err(err) => panic!("from_os_rng failed: {}", err),
} }
Self::from_seed(seed)
}
}
// Implement `RngCore` for references to an `RngCore`.
// Force inlining all functions, so that it is up to the `RngCore`
// implementation and the optimizer to decide on inlining.
impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
(**self).next_u32()
} }
#[inline(always)] /// Creates a new instance of the RNG seeded via [`getrandom`] without unwrapping
fn next_u64(&mut self) -> u64 { /// potential [`getrandom`] errors.
(**self).next_u64() ///
} /// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an
/// issue, one may prefer to seed from a local PRNG, e.g.
#[inline(always)] /// `from_rng(&mut thread_rng()).unwrap()`.
fn fill_bytes(&mut self, dest: &mut [u8]) { ///
(**self).fill_bytes(dest) /// [`getrandom`]: https://docs.rs/getrandom
} #[cfg(feature = "getrandom")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[inline(always)] fn try_from_os_rng() -> Result<Self, getrandom::Error> {
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { let mut seed = Self::Seed::default();
(**self).try_fill_bytes(dest) getrandom::getrandom(seed.as_mut())?;
} let res = Self::from_seed(seed);
} Ok(res)
// Implement `RngCore` for boxed references to an `RngCore`.
// Force inlining all functions, so that it is up to the `RngCore`
// implementation and the optimizer to decide on inlining.
#[cfg(feature = "alloc")]
impl<R: RngCore + ?Sized> RngCore for Box<R> {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
(**self).next_u32()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
(**self).next_u64()
}
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
(**self).fill_bytes(dest)
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
(**self).try_fill_bytes(dest)
} }
} }
@ -453,38 +471,32 @@ impl<R: RngCore + ?Sized> RngCore for Box<R> {
/// ```no_run /// ```no_run
/// # use std::{io, io::Read}; /// # use std::{io, io::Read};
/// # use std::fs::File; /// # use std::fs::File;
/// # use rand_core::{OsRng, RngCore}; /// # use rand_core::{OsRng, TryRngCore};
/// ///
/// io::copy(&mut OsRng.read_adapter().take(100), &mut File::create("/tmp/random.bytes").unwrap()).unwrap(); /// io::copy(&mut OsRng.read_adapter().take(100), &mut File::create("/tmp/random.bytes").unwrap()).unwrap();
/// ``` /// ```
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub struct RngReadAdapter<'a, R: RngCore + ?Sized> { pub struct RngReadAdapter<'a, R: TryRngCore + ?Sized> {
inner: &'a mut R, inner: &'a mut R,
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<R: RngCore + ?Sized> std::io::Read for RngReadAdapter<'_, R> { impl<R: TryRngCore + ?Sized> std::io::Read for RngReadAdapter<'_, R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
self.inner.try_fill_bytes(buf)?; self.inner.try_fill_bytes(buf).map_err(|err| {
std::io::Error::new(std::io::ErrorKind::Other, std::format!("RNG error: {err}"))
})?;
Ok(buf.len()) Ok(buf.len())
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<R: RngCore + ?Sized> std::fmt::Debug for RngReadAdapter<'_, R> { impl<R: TryRngCore + ?Sized> std::fmt::Debug for RngReadAdapter<'_, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReadAdapter").finish() f.debug_struct("ReadAdapter").finish()
} }
} }
// Implement `CryptoRng` for references to a `CryptoRng`.
impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
// Implement `CryptoRng` for boxed references to a `CryptoRng`.
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -8,7 +8,7 @@
//! Interface to the random number generator of the operating system. //! Interface to the random number generator of the operating system.
use crate::{impls, CryptoRng, Error, RngCore}; use crate::{TryCryptoRng, TryRngCore};
use getrandom::getrandom; use getrandom::getrandom;
/// A random number generator that retrieves randomness from the /// A random number generator that retrieves randomness from the
@ -36,11 +36,11 @@ use getrandom::getrandom;
/// ///
/// # Usage example /// # Usage example
/// ``` /// ```
/// use rand_core::{RngCore, OsRng}; /// use rand_core::{TryRngCore, OsRng};
/// ///
/// let mut key = [0u8; 16]; /// let mut key = [0u8; 16];
/// OsRng.fill_bytes(&mut key); /// OsRng.try_fill_bytes(&mut key).unwrap();
/// let random_u64 = OsRng.next_u64(); /// let random_u64 = OsRng.try_next_u64().unwrap();
/// ``` /// ```
/// ///
/// [getrandom]: https://crates.io/crates/getrandom /// [getrandom]: https://crates.io/crates/getrandom
@ -48,39 +48,41 @@ use getrandom::getrandom;
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct OsRng; pub struct OsRng;
impl CryptoRng for OsRng {} impl TryRngCore for OsRng {
type Error = getrandom::Error;
impl RngCore for OsRng { #[inline]
fn next_u32(&mut self) -> u32 { fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
impls::next_u32_via_fill(self) let mut buf = [0u8; 4];
getrandom(&mut buf)?;
Ok(u32::from_ne_bytes(buf))
} }
fn next_u64(&mut self) -> u64 { #[inline]
impls::next_u64_via_fill(self) fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
let mut buf = [0u8; 8];
getrandom(&mut buf)?;
Ok(u64::from_ne_bytes(buf))
} }
fn fill_bytes(&mut self, dest: &mut [u8]) { #[inline]
if let Err(e) = self.try_fill_bytes(dest) { fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
panic!("Error: {}", e);
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
getrandom(dest)?; getrandom(dest)?;
Ok(()) Ok(())
} }
} }
impl TryCryptoRng for OsRng {}
#[test] #[test]
fn test_os_rng() { fn test_os_rng() {
let x = OsRng.next_u64(); let x = OsRng.try_next_u64().unwrap();
let y = OsRng.next_u64(); let y = OsRng.try_next_u64().unwrap();
assert!(x != 0); assert!(x != 0);
assert!(x != y); assert!(x != y);
} }
#[test] #[test]
fn test_construction() { fn test_construction() {
let mut rng = OsRng::default(); assert!(OsRng.try_next_u64().unwrap() != 0);
assert!(rng.next_u64() != 0);
} }

View File

@ -23,7 +23,7 @@ fn unit_sphere() {
let h = Histogram100::with_const_width(-1., 1.); let h = Histogram100::with_const_width(-1., 1.);
let mut histograms = [h.clone(), h.clone(), h]; let mut histograms = [h.clone(), h.clone(), h];
let dist = rand_distr::UnitSphere; let dist = rand_distr::UnitSphere;
let mut rng = rand_pcg::Pcg32::from_entropy(); let mut rng = rand_pcg::Pcg32::from_os_rng();
for _ in 0..N_SAMPLES { for _ in 0..N_SAMPLES {
let v: [f64; 3] = dist.sample(&mut rng); let v: [f64; 3] = dist.sample(&mut rng);
for i in 0..N_DIM { for i in 0..N_DIM {
@ -51,7 +51,7 @@ fn unit_circle() {
use core::f64::consts::PI; use core::f64::consts::PI;
let mut h = Histogram100::with_const_width(-PI, PI); let mut h = Histogram100::with_const_width(-PI, PI);
let dist = rand_distr::UnitCircle; let dist = rand_distr::UnitCircle;
let mut rng = rand_pcg::Pcg32::from_entropy(); let mut rng = rand_pcg::Pcg32::from_os_rng();
for _ in 0..N_SAMPLES { for _ in 0..N_SAMPLES {
let v: [f64; 2] = dist.sample(&mut rng); let v: [f64; 2] = dist.sample(&mut rng);
h.add(v[0].atan2(v[1])).unwrap(); h.add(v[0].atan2(v[1])).unwrap();

View File

@ -47,7 +47,7 @@
//! use rand::{Rng, SeedableRng}; //! use rand::{Rng, SeedableRng};
//! use rand_pcg::Pcg64Mcg; //! use rand_pcg::Pcg64Mcg;
//! //!
//! let mut rng = Pcg64Mcg::from_entropy(); //! let mut rng = Pcg64Mcg::from_os_rng();
//! let x: f64 = rng.gen(); //! let x: f64 = rng.gen();
//! ``` //! ```

View File

@ -14,7 +14,7 @@
const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645; const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645;
use core::fmt; use core::fmt;
use rand_core::{impls, le, Error, RngCore, SeedableRng}; use rand_core::{impls, le, RngCore, SeedableRng};
#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize}; #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
/// A PCG random number generator (XSL RR 128/64 (LCG) variant). /// A PCG random number generator (XSL RR 128/64 (LCG) variant).
@ -151,12 +151,6 @@ impl RngCore for Lcg128Xsl64 {
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest) impls::fill_bytes_via_next(self, dest)
} }
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
} }
@ -261,12 +255,6 @@ impl RngCore for Mcg128Xsl64 {
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest) impls::fill_bytes_via_next(self, dest)
} }
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
} }
#[inline(always)] #[inline(always)]

View File

@ -14,7 +14,7 @@
const MULTIPLIER: u64 = 15750249268501108917; const MULTIPLIER: u64 = 15750249268501108917;
use core::fmt; use core::fmt;
use rand_core::{impls, le, Error, RngCore, SeedableRng}; use rand_core::{impls, le, RngCore, SeedableRng};
#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize}; #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
/// A PCG random number generator (CM DXSM 128/64 (LCG) variant). /// A PCG random number generator (CM DXSM 128/64 (LCG) variant).
@ -148,21 +148,15 @@ impl RngCore for Lcg128CmDxsm64 {
#[inline] #[inline]
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
let val = output_dxsm(self.state); let res = output_dxsm(self.state);
self.step(); self.step();
val res
} }
#[inline] #[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest) impls::fill_bytes_via_next(self, dest)
} }
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
} }
#[inline(always)] #[inline(always)]

View File

@ -11,7 +11,7 @@
//! PCG random number generators //! PCG random number generators
use core::fmt; use core::fmt;
use rand_core::{impls, le, Error, RngCore, SeedableRng}; use rand_core::{impls, le, RngCore, SeedableRng};
#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize}; #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
// This is the default multiplier used by PCG for 64-bit state. // This is the default multiplier used by PCG for 64-bit state.
@ -160,10 +160,4 @@ impl RngCore for Lcg64Xsh32 {
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest) impls::fill_bytes_via_next(self, dest)
} }
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
} }

View File

@ -23,7 +23,7 @@ fn test_lcg128cmdxsm64_construction() {
let mut rng1 = Lcg128CmDxsm64::from_seed(seed); let mut rng1 = Lcg128CmDxsm64::from_seed(seed);
assert_eq!(rng1.next_u64(), 12201417210360370199); assert_eq!(rng1.next_u64(), 12201417210360370199);
let mut rng2 = Lcg128CmDxsm64::from_rng(&mut rng1).unwrap(); let mut rng2 = Lcg128CmDxsm64::from_rng(&mut rng1);
assert_eq!(rng2.next_u64(), 11487972556150888383); assert_eq!(rng2.next_u64(), 11487972556150888383);
let mut rng3 = Lcg128CmDxsm64::seed_from_u64(0); let mut rng3 = Lcg128CmDxsm64::seed_from_u64(0);

View File

@ -23,7 +23,7 @@ fn test_lcg128xsl64_construction() {
let mut rng1 = Lcg128Xsl64::from_seed(seed); let mut rng1 = Lcg128Xsl64::from_seed(seed);
assert_eq!(rng1.next_u64(), 8740028313290271629); assert_eq!(rng1.next_u64(), 8740028313290271629);
let mut rng2 = Lcg128Xsl64::from_rng(&mut rng1).unwrap(); let mut rng2 = Lcg128Xsl64::from_rng(&mut rng1);
assert_eq!(rng2.next_u64(), 1922280315005786345); assert_eq!(rng2.next_u64(), 1922280315005786345);
let mut rng3 = Lcg128Xsl64::seed_from_u64(0); let mut rng3 = Lcg128Xsl64::seed_from_u64(0);

View File

@ -21,7 +21,7 @@ fn test_lcg64xsh32_construction() {
let mut rng1 = Lcg64Xsh32::from_seed(seed); let mut rng1 = Lcg64Xsh32::from_seed(seed);
assert_eq!(rng1.next_u64(), 1204678643940597513); assert_eq!(rng1.next_u64(), 1204678643940597513);
let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1).unwrap(); let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1);
assert_eq!(rng2.next_u64(), 12384929573776311845); assert_eq!(rng2.next_u64(), 12384929573776311845);
let mut rng3 = Lcg64Xsh32::seed_from_u64(0); let mut rng3 = Lcg64Xsh32::seed_from_u64(0);

View File

@ -21,7 +21,7 @@ fn test_mcg128xsl64_construction() {
let mut rng1 = Mcg128Xsl64::from_seed(seed); let mut rng1 = Mcg128Xsl64::from_seed(seed);
assert_eq!(rng1.next_u64(), 7071994460355047496); assert_eq!(rng1.next_u64(), 7071994460355047496);
let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1).unwrap(); let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1);
assert_eq!(rng2.next_u64(), 12300796107712034932); assert_eq!(rng2.next_u64(), 12300796107712034932);
let mut rng3 = Mcg128Xsl64::seed_from_u64(0); let mut rng3 = Mcg128Xsl64::seed_from_u64(0);

View File

@ -10,9 +10,8 @@
//! Distribution trait and associates //! Distribution trait and associates
use crate::Rng; use crate::Rng;
#[cfg(feature = "alloc")] use alloc::string::String;
use core::iter; use core::iter;
#[cfg(feature = "alloc")]
use alloc::string::String;
/// Types (distributions) that can be used to create a random instance of `T`. /// Types (distributions) that can be used to create a random instance of `T`.
/// ///
@ -229,9 +228,7 @@ mod tests {
#[test] #[test]
fn test_make_an_iter() { fn test_make_an_iter() {
fn ten_dice_rolls_other_than_five<R: Rng>( fn ten_dice_rolls_other_than_five<R: Rng>(rng: &mut R) -> impl Iterator<Item = i32> + '_ {
rng: &mut R,
) -> impl Iterator<Item = i32> + '_ {
Uniform::new_inclusive(1, 6) Uniform::new_inclusive(1, 6)
.unwrap() .unwrap()
.sample_iter(rng) .sample_iter(rng)
@ -251,8 +248,8 @@ mod tests {
#[test] #[test]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn test_dist_string() { fn test_dist_string() {
use core::str;
use crate::distributions::{Alphanumeric, DistString, Standard}; use crate::distributions::{Alphanumeric, DistString, Standard};
use core::str;
let mut rng = crate::test::rng(213); let mut rng = crate::test::rng(213);
let s1 = Alphanumeric.sample_string(&mut rng, 20); let s1 = Alphanumeric.sample_string(&mut rng, 20);

View File

@ -191,7 +191,7 @@ use crate::Rng;
/// use rand::prelude::*; /// use rand::prelude::*;
/// use rand::distributions::Standard; /// use rand::distributions::Standard;
/// ///
/// let val: f32 = StdRng::from_entropy().sample(Standard); /// let val: f32 = StdRng::from_os_rng().sample(Standard);
/// println!("f32 from [0, 1): {}", val); /// println!("f32 from [0, 1): {}", val);
/// ``` /// ```
/// ///

View File

@ -57,8 +57,8 @@
clippy::nonminimal_bool clippy::nonminimal_bool
)] )]
#[cfg(feature = "std")] extern crate std;
#[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "alloc")] extern crate alloc;
#[cfg(feature = "std")] extern crate std;
#[allow(unused)] #[allow(unused)]
macro_rules! trace { ($($x:tt)*) => ( macro_rules! trace { ($($x:tt)*) => (
@ -92,7 +92,7 @@ macro_rules! error { ($($x:tt)*) => (
) } ) }
// Re-exports from rand_core // Re-exports from rand_core
pub use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; pub use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};
// Public modules // Public modules
pub mod distributions; pub mod distributions;
@ -154,7 +154,10 @@ use crate::distributions::{Distribution, Standard};
/// [`Standard`]: distributions::Standard /// [`Standard`]: distributions::Standard
/// [`ThreadRng`]: rngs::ThreadRng /// [`ThreadRng`]: rngs::ThreadRng
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))] #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))))] #[cfg_attr(
doc_cfg,
doc(cfg(all(feature = "std", feature = "std_rng", feature = "getrandom")))
)]
#[inline] #[inline]
pub fn random<T>() -> T pub fn random<T>() -> T
where Standard: Distribution<T> { where Standard: Distribution<T> {

View File

@ -14,7 +14,7 @@
//! //!
//! ``` //! ```
//! use rand::prelude::*; //! use rand::prelude::*;
//! # let mut r = StdRng::from_rng(thread_rng()).unwrap(); //! # let mut r = StdRng::from_rng(thread_rng());
//! # let _: f32 = r.random(); //! # let _: f32 = r.random();
//! ``` //! ```
@ -23,7 +23,8 @@
#[doc(no_inline)] #[doc(no_inline)]
pub use crate::rngs::SmallRng; pub use crate::rngs::SmallRng;
#[cfg(feature = "std_rng")] #[cfg(feature = "std_rng")]
#[doc(no_inline)] pub use crate::rngs::StdRng; #[doc(no_inline)]
pub use crate::rngs::StdRng;
#[doc(no_inline)] #[doc(no_inline)]
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))] #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
pub use crate::rngs::ThreadRng; pub use crate::rngs::ThreadRng;

View File

@ -13,7 +13,7 @@ use crate::distributions::uniform::{SampleRange, SampleUniform};
use crate::distributions::{self, Distribution, Standard}; use crate::distributions::{self, Distribution, Standard};
use core::num::Wrapping; use core::num::Wrapping;
use core::{mem, slice}; use core::{mem, slice};
use rand_core::{Error, RngCore}; use rand_core::RngCore;
/// An automatically-implemented extension trait on [`RngCore`] providing high-level /// An automatically-implemented extension trait on [`RngCore`] providing high-level
/// generic methods for sampling values and other convenience methods. /// generic methods for sampling values and other convenience methods.
@ -224,8 +224,6 @@ pub trait Rng: RngCore {
/// The distribution is expected to be uniform with portable results, but /// The distribution is expected to be uniform with portable results, but
/// this cannot be guaranteed for third-party implementations. /// this cannot be guaranteed for third-party implementations.
/// ///
/// This is identical to [`try_fill`] except that it panics on error.
///
/// # Example /// # Example
/// ///
/// ``` /// ```
@ -236,38 +234,9 @@ pub trait Rng: RngCore {
/// ``` /// ```
/// ///
/// [`fill_bytes`]: RngCore::fill_bytes /// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill`]: Rng::try_fill
#[track_caller] #[track_caller]
fn fill<T: Fill + ?Sized>(&mut self, dest: &mut T) { fn fill<T: Fill + ?Sized>(&mut self, dest: &mut T) {
dest.try_fill(self).expect("Rng::fill failed") dest.fill(self)
}
/// Fill any type implementing [`Fill`] with random data
///
/// The distribution is expected to be uniform with portable results, but
/// this cannot be guaranteed for third-party implementations.
///
/// This is identical to [`fill`] except that it forwards errors.
///
/// # Example
///
/// ```
/// # use rand::Error;
/// use rand::{thread_rng, Rng};
///
/// # fn try_inner() -> Result<(), Error> {
/// let mut arr = [0u64; 4];
/// thread_rng().try_fill(&mut arr[..])?;
/// # Ok(())
/// # }
///
/// # try_inner().unwrap()
/// ```
///
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
/// [`fill`]: Rng::fill
fn try_fill<T: Fill + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> {
dest.try_fill(self)
} }
/// Return a bool with a probability `p` of being true. /// Return a bool with a probability `p` of being true.
@ -335,9 +304,12 @@ pub trait Rng: RngCore {
/// Alias for [`Rng::random`]. /// Alias for [`Rng::random`].
#[inline] #[inline]
#[deprecated(since="0.9.0", note="Renamed to `random` to avoid conflict with the new `gen` keyword in Rust 2024.")] #[deprecated(
since = "0.9.0",
note = "Renamed to `random` to avoid conflict with the new `gen` keyword in Rust 2024."
)]
fn gen<T>(&mut self) -> T fn gen<T>(&mut self) -> T
where Standard: Distribution<T> { where Standard: Distribution<T> {
self.random() self.random()
} }
} }
@ -353,18 +325,17 @@ impl<R: RngCore + ?Sized> Rng for R {}
/// [Chapter on Portability](https://rust-random.github.io/book/portability.html)). /// [Chapter on Portability](https://rust-random.github.io/book/portability.html)).
pub trait Fill { pub trait Fill {
/// Fill self with random data /// Fill self with random data
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error>; fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R);
} }
macro_rules! impl_fill_each { macro_rules! impl_fill_each {
() => {}; () => {};
($t:ty) => { ($t:ty) => {
impl Fill for [$t] { impl Fill for [$t] {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> { fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
for elt in self.iter_mut() { for elt in self.iter_mut() {
*elt = rng.random(); *elt = rng.random();
} }
Ok(())
} }
} }
}; };
@ -377,8 +348,8 @@ macro_rules! impl_fill_each {
impl_fill_each!(bool, char, f32, f64,); impl_fill_each!(bool, char, f32, f64,);
impl Fill for [u8] { impl Fill for [u8] {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> { fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
rng.try_fill_bytes(self) rng.fill_bytes(self)
} }
} }
@ -387,37 +358,35 @@ macro_rules! impl_fill {
($t:ty) => { ($t:ty) => {
impl Fill for [$t] { impl Fill for [$t] {
#[inline(never)] // in micro benchmarks, this improves performance #[inline(never)] // in micro benchmarks, this improves performance
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> { fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
if self.len() > 0 { if self.len() > 0 {
rng.try_fill_bytes(unsafe { rng.fill_bytes(unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr() slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut u8, as *mut u8,
mem::size_of_val(self) mem::size_of_val(self)
) )
})?; });
for x in self { for x in self {
*x = x.to_le(); *x = x.to_le();
} }
} }
Ok(())
} }
} }
impl Fill for [Wrapping<$t>] { impl Fill for [Wrapping<$t>] {
#[inline(never)] #[inline(never)]
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> { fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
if self.len() > 0 { if self.len() > 0 {
rng.try_fill_bytes(unsafe { rng.fill_bytes(unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr() slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut u8, as *mut u8,
self.len() * mem::size_of::<$t>() self.len() * mem::size_of::<$t>()
) )
})?; });
for x in self { for x in self {
*x = Wrapping(x.0.to_le()); *x = Wrapping(x.0.to_le());
} }
} }
Ok(())
} }
} }
}; };
@ -435,8 +404,8 @@ impl_fill!(i8, i16, i32, i64, isize, i128,);
impl<T, const N: usize> Fill for [T; N] impl<T, const N: usize> Fill for [T; N]
where [T]: Fill where [T]: Fill
{ {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> { fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
self[..].try_fill(rng) <[T] as Fill>::fill(self, rng)
} }
} }
@ -543,24 +512,23 @@ mod test {
#[test] #[test]
#[should_panic] #[should_panic]
#[allow(clippy::reversed_empty_ranges)]
fn test_gen_range_panic_int() { fn test_gen_range_panic_int() {
#![allow(clippy::reversed_empty_ranges)]
let mut r = rng(102); let mut r = rng(102);
r.gen_range(5..-2); r.gen_range(5..-2);
} }
#[test] #[test]
#[should_panic] #[should_panic]
#[allow(clippy::reversed_empty_ranges)]
fn test_gen_range_panic_usize() { fn test_gen_range_panic_usize() {
#![allow(clippy::reversed_empty_ranges)]
let mut r = rng(103); let mut r = rng(103);
r.gen_range(5..2); r.gen_range(5..2);
} }
#[test] #[test]
#[allow(clippy::bool_assert_comparison)]
fn test_gen_bool() { fn test_gen_bool() {
#![allow(clippy::bool_assert_comparison)]
let mut r = rng(105); let mut r = rng(105);
for _ in 0..5 { for _ in 0..5 {
assert_eq!(r.gen_bool(0.0), false); assert_eq!(r.gen_bool(0.0), false);
@ -568,6 +536,16 @@ mod test {
} }
} }
#[test]
fn test_rng_mut_ref() {
fn use_rng(mut r: impl Rng) {
let _ = r.next_u32();
}
let mut rng = rng(109);
use_rng(&mut rng);
}
#[test] #[test]
fn test_rng_trait_object() { fn test_rng_trait_object() {
use crate::distributions::{Distribution, Standard}; use crate::distributions::{Distribution, Standard};

View File

@ -8,10 +8,9 @@
//! Mock random number generator //! Mock random number generator
use rand_core::{impls, Error, RngCore}; use rand_core::{impls, RngCore};
#[cfg(feature = "serde1")] #[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
use serde::{Serialize, Deserialize};
/// A mock generator yielding very predictable output /// A mock generator yielding very predictable output
/// ///
@ -64,27 +63,22 @@ impl RngCore for StepRng {
#[inline] #[inline]
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
let result = self.v; let res = self.v;
self.v = self.v.wrapping_add(self.a); self.v = self.v.wrapping_add(self.a);
result res
} }
#[inline] #[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dst: &mut [u8]) {
impls::fill_bytes_via_next(self, dest); impls::fill_bytes_via_next(self, dst)
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
} }
} }
rand_core::impl_try_rng_from_rng_core!(StepRng);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[cfg(any(feature = "alloc", feature = "serde1"))] #[cfg(any(feature = "alloc", feature = "serde1"))] use super::StepRng;
use super::StepRng;
#[test] #[test]
#[cfg(feature = "serde1")] #[cfg(feature = "serde1")]
@ -94,18 +88,16 @@ mod tests {
bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap(); bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap();
assert_eq!(some_rng.v, de_some_rng.v); assert_eq!(some_rng.v, de_some_rng.v);
assert_eq!(some_rng.a, de_some_rng.a); assert_eq!(some_rng.a, de_some_rng.a);
} }
#[test] #[test]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn test_bool() { fn test_bool() {
use crate::{Rng, distributions::Standard}; use crate::{distributions::Standard, Rng};
// If this result ever changes, update doc on StepRng! // If this result ever changes, update doc on StepRng!
let rng = StepRng::new(0, 1 << 31); let rng = StepRng::new(0, 1 << 31);
let result: alloc::vec::Vec<bool> = let result: alloc::vec::Vec<bool> = rng.sample_iter(Standard).take(6).collect();
rng.sample_iter(Standard).take(6).collect();
assert_eq!(&result, &[false, true, false, true, false, true]); assert_eq!(&result, &[false, true, false, true, false, true]);
} }
} }

View File

@ -42,7 +42,7 @@
//! - `from_seed` accepts a type specific to the PRNG //! - `from_seed` accepts a type specific to the PRNG
//! - `from_rng` allows a PRNG to be seeded from any other RNG //! - `from_rng` allows a PRNG to be seeded from any other RNG
//! - `seed_from_u64` allows any PRNG to be seeded from a `u64` insecurely //! - `seed_from_u64` allows any PRNG to be seeded from a `u64` insecurely
//! - `from_entropy` securely seeds a PRNG from fresh entropy //! - `from_os_rng` securely seeds a PRNG from system randomness source
//! //!
//! Use the [`rand_core`] crate when implementing your own RNGs. //! Use the [`rand_core`] crate when implementing your own RNGs.
//! //!
@ -102,18 +102,21 @@ pub use reseeding::ReseedingRng;
pub mod mock; // Public so we don't export `StepRng` directly, making it a bit pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
// more clear it is intended for testing. // more clear it is intended for testing.
#[cfg(all(feature = "small_rng", target_pointer_width = "64"))] #[cfg(feature = "small_rng")] mod small;
mod xoshiro256plusplus;
#[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))] #[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))]
mod xoshiro128plusplus; mod xoshiro128plusplus;
#[cfg(feature = "small_rng")] mod small; #[cfg(all(feature = "small_rng", target_pointer_width = "64"))]
mod xoshiro256plusplus;
#[cfg(feature = "std_rng")] mod std; #[cfg(feature = "std_rng")] mod std;
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))] pub(crate) mod thread; #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
pub(crate) mod thread;
#[cfg(feature = "small_rng")] pub use self::small::SmallRng; #[cfg(feature = "small_rng")] pub use self::small::SmallRng;
#[cfg(feature = "std_rng")] pub use self::std::StdRng; #[cfg(feature = "std_rng")] pub use self::std::StdRng;
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))] pub use self::thread::ThreadRng; #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
pub use self::thread::ThreadRng;
#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[cfg(feature = "getrandom")] pub use rand_core::OsRng; #[cfg(feature = "getrandom")]
pub use rand_core::OsRng;

View File

@ -12,8 +12,8 @@
use core::mem::size_of_val; use core::mem::size_of_val;
use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng}; use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};
/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the /// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
/// ability to reseed it. /// ability to reseed it.
@ -59,7 +59,7 @@ use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
/// use rand::rngs::OsRng; /// use rand::rngs::OsRng;
/// use rand::rngs::ReseedingRng; /// use rand::rngs::ReseedingRng;
/// ///
/// let prng = ChaCha20Core::from_entropy(); /// let prng = ChaCha20Core::from_os_rng();
/// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng); /// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng);
/// ///
/// println!("{}", reseeding_rng.random::<u64>()); /// println!("{}", reseeding_rng.random::<u64>());
@ -75,12 +75,12 @@ use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>) pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
where where
R: BlockRngCore + SeedableRng, R: BlockRngCore + SeedableRng,
Rsdr: RngCore; Rsdr: TryRngCore;
impl<R, Rsdr> ReseedingRng<R, Rsdr> impl<R, Rsdr> ReseedingRng<R, Rsdr>
where where
R: BlockRngCore + SeedableRng, R: BlockRngCore + SeedableRng,
Rsdr: RngCore, Rsdr: TryRngCore,
{ {
/// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG
/// to use as reseeder. /// to use as reseeder.
@ -95,7 +95,7 @@ where
/// Immediately reseed the generator /// Immediately reseed the generator
/// ///
/// This discards any remaining random data in the cache. /// This discards any remaining random data in the cache.
pub fn reseed(&mut self) -> Result<(), Error> { pub fn reseed(&mut self) -> Result<(), Rsdr::Error> {
self.0.reset(); self.0.reset();
self.0.core.reseed() self.0.core.reseed()
} }
@ -103,9 +103,10 @@ where
// TODO: this should be implemented for any type where the inner type // TODO: this should be implemented for any type where the inner type
// implements RngCore, but we can't specify that because ReseedingCore is private // implements RngCore, but we can't specify that because ReseedingCore is private
impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr> impl<R, Rsdr> RngCore for ReseedingRng<R, Rsdr>
where where
R: BlockRngCore<Item = u32> + SeedableRng, R: BlockRngCore<Item = u32> + SeedableRng,
Rsdr: TryRngCore,
{ {
#[inline(always)] #[inline(always)]
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
@ -120,16 +121,12 @@ where
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
self.0.fill_bytes(dest) self.0.fill_bytes(dest)
} }
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.0.try_fill_bytes(dest)
}
} }
impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr> impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr>
where where
R: BlockRngCore + SeedableRng + Clone, R: BlockRngCore + SeedableRng + Clone,
Rsdr: RngCore + Clone, Rsdr: TryRngCore + Clone,
{ {
fn clone(&self) -> ReseedingRng<R, Rsdr> { fn clone(&self) -> ReseedingRng<R, Rsdr> {
// Recreating `BlockRng` seems easier than cloning it and resetting // Recreating `BlockRng` seems easier than cloning it and resetting
@ -141,7 +138,7 @@ where
impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr> impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
where where
R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng, R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng,
Rsdr: CryptoRng, Rsdr: TryCryptoRng,
{ {
} }
@ -156,7 +153,7 @@ struct ReseedingCore<R, Rsdr> {
impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr> impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr>
where where
R: BlockRngCore + SeedableRng, R: BlockRngCore + SeedableRng,
Rsdr: RngCore, Rsdr: TryRngCore,
{ {
type Item = <R as BlockRngCore>::Item; type Item = <R as BlockRngCore>::Item;
type Results = <R as BlockRngCore>::Results; type Results = <R as BlockRngCore>::Results;
@ -177,7 +174,7 @@ where
impl<R, Rsdr> ReseedingCore<R, Rsdr> impl<R, Rsdr> ReseedingCore<R, Rsdr>
where where
R: BlockRngCore + SeedableRng, R: BlockRngCore + SeedableRng,
Rsdr: RngCore, Rsdr: TryRngCore,
{ {
/// Create a new `ReseedingCore`. /// Create a new `ReseedingCore`.
fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
@ -202,8 +199,8 @@ where
} }
/// Reseed the internal PRNG. /// Reseed the internal PRNG.
fn reseed(&mut self) -> Result<(), Error> { fn reseed(&mut self) -> Result<(), Rsdr::Error> {
R::from_rng(&mut self.reseeder).map(|result| { R::try_from_rng(&mut self.reseeder).map(|result| {
self.bytes_until_reseed = self.threshold; self.bytes_until_reseed = self.threshold;
self.inner = result self.inner = result
}) })
@ -228,7 +225,7 @@ where
impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr> impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr>
where where
R: BlockRngCore + SeedableRng + Clone, R: BlockRngCore + SeedableRng + Clone,
Rsdr: RngCore + Clone, Rsdr: TryRngCore + Clone,
{ {
fn clone(&self) -> ReseedingCore<R, Rsdr> { fn clone(&self) -> ReseedingCore<R, Rsdr> {
ReseedingCore { ReseedingCore {
@ -243,22 +240,23 @@ where
impl<R, Rsdr> CryptoBlockRng for ReseedingCore<R, Rsdr> impl<R, Rsdr> CryptoBlockRng for ReseedingCore<R, Rsdr>
where where
R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng, R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng,
Rsdr: CryptoRng, Rsdr: TryCryptoRng,
{} {
}
#[cfg(feature = "std_rng")] #[cfg(feature = "std_rng")]
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{Rng, SeedableRng};
use crate::rngs::mock::StepRng; use crate::rngs::mock::StepRng;
use crate::rngs::std::Core; use crate::rngs::std::Core;
use crate::{Rng, SeedableRng};
use super::ReseedingRng; use super::ReseedingRng;
#[test] #[test]
fn test_reseeding() { fn test_reseeding() {
let mut zero = StepRng::new(0, 0); let mut zero = StepRng::new(0, 0);
let rng = Core::from_rng(&mut zero).unwrap(); let rng = Core::from_rng(&mut zero);
let thresh = 1; // reseed every time the buffer is exhausted let thresh = 1; // reseed every time the buffer is exhausted
let mut reseeding = ReseedingRng::new(rng, thresh, zero); let mut reseeding = ReseedingRng::new(rng, thresh, zero);
@ -276,11 +274,10 @@ mod test {
} }
#[test] #[test]
#[allow(clippy::redundant_clone)]
fn test_clone_reseeding() { fn test_clone_reseeding() {
#![allow(clippy::redundant_clone)]
let mut zero = StepRng::new(0, 0); let mut zero = StepRng::new(0, 0);
let rng = Core::from_rng(&mut zero).unwrap(); let rng = Core::from_rng(&mut zero);
let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero); let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero);
let first: u32 = rng1.random(); let first: u32 = rng1.random();

View File

@ -8,7 +8,7 @@
//! A small fast RNG //! A small fast RNG
use rand_core::{Error, RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus; type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
@ -55,15 +55,12 @@ impl RngCore for SmallRng {
#[inline(always)] #[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
self.0.fill_bytes(dest); self.0.fill_bytes(dest)
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.0.try_fill_bytes(dest)
} }
} }
rand_core::impl_try_rng_from_rng_core!(SmallRng);
impl SmallRng { impl SmallRng {
/// Construct an instance seeded from another `Rng` /// Construct an instance seeded from another `Rng`
/// ///
@ -76,8 +73,8 @@ impl SmallRng {
/// let rng = SmallRng::from_rng(rand::thread_rng()); /// let rng = SmallRng::from_rng(rand::thread_rng());
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { pub fn from_rng<R: RngCore>(rng: R) -> Self {
Rng::from_rng(rng).map(SmallRng) Self(Rng::from_rng(rng))
} }
/// Construct an instance seeded from the thread-local RNG /// Construct an instance seeded from the thread-local RNG

View File

@ -8,7 +8,7 @@
//! The standard RNG //! The standard RNG
use crate::{CryptoRng, Error, RngCore, SeedableRng}; use rand_core::{CryptoRng, RngCore, SeedableRng};
#[cfg(any(test, feature = "getrandom"))] #[cfg(any(test, feature = "getrandom"))]
pub(crate) use rand_chacha::ChaCha12Core as Core; pub(crate) use rand_chacha::ChaCha12Core as Core;
@ -20,7 +20,7 @@ use rand_chacha::ChaCha12Rng as Rng;
/// (meaning a cryptographically secure PRNG). /// (meaning a cryptographically secure PRNG).
/// ///
/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please /// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
/// see this relevant [rand issue] for the discussion. This may change as new /// see this relevant [rand issue] for the discussion. This may change as new
/// evidence of cipher security and performance becomes available. /// evidence of cipher security and performance becomes available.
/// ///
/// The algorithm is deterministic but should not be considered reproducible /// The algorithm is deterministic but should not be considered reproducible
@ -46,13 +46,8 @@ impl RngCore for StdRng {
} }
#[inline(always)] #[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dst: &mut [u8]) {
self.0.fill_bytes(dest); self.0.fill_bytes(dst)
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.0.try_fill_bytes(dest)
} }
} }
@ -64,15 +59,11 @@ impl SeedableRng for StdRng {
fn from_seed(seed: Self::Seed) -> Self { fn from_seed(seed: Self::Seed) -> Self {
StdRng(Rng::from_seed(seed)) StdRng(Rng::from_seed(seed))
} }
#[inline(always)]
fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
Rng::from_rng(rng).map(StdRng)
}
} }
impl CryptoRng for StdRng {} impl CryptoRng for StdRng {}
rand_core::impl_try_crypto_rng_from_crypto_rng!(StdRng);
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -92,7 +83,7 @@ mod test {
let mut rng0 = StdRng::from_seed(seed); let mut rng0 = StdRng::from_seed(seed);
let x0 = rng0.next_u64(); let x0 = rng0.next_u64();
let mut rng1 = StdRng::from_rng(rng0).unwrap(); let mut rng1 = StdRng::from_rng(&mut rng0);
let x1 = rng1.next_u64(); let x1 = rng1.next_u64();
assert_eq!([x0, x1], target); assert_eq!([x0, x1], target);

View File

@ -9,14 +9,15 @@
//! Thread-local random number generator //! Thread-local random number generator
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::thread_local; use std::thread_local;
use std::fmt;
use rand_core::{CryptoRng, RngCore, SeedableRng};
use super::std::Core; use super::std::Core;
use crate::rngs::ReseedingRng;
use crate::rngs::OsRng; use crate::rngs::OsRng;
use crate::{CryptoRng, Error, RngCore, SeedableRng}; use crate::rngs::ReseedingRng;
// Rationale for using `UnsafeCell` in `ThreadRng`: // Rationale for using `UnsafeCell` in `ThreadRng`:
// //
@ -76,7 +77,10 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
/// ///
/// [`ReseedingRng`]: crate::rngs::ReseedingRng /// [`ReseedingRng`]: crate::rngs::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng /// [`StdRng`]: crate::rngs::StdRng
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))))] #[cfg_attr(
doc_cfg,
doc(cfg(all(feature = "std", feature = "std_rng", feature = "getrandom")))
)]
#[derive(Clone)] #[derive(Clone)]
pub struct ThreadRng { pub struct ThreadRng {
// Rc is explicitly !Send and !Sync // Rc is explicitly !Send and !Sync
@ -87,7 +91,7 @@ impl ThreadRng {
/// Immediately reseed the generator /// Immediately reseed the generator
/// ///
/// This discards any remaining random data in the cache. /// This discards any remaining random data in the cache.
pub fn reseed(&mut self) -> Result<(), Error> { pub fn reseed(&mut self) -> Result<(), rand_core::getrandom::Error> {
// SAFETY: We must make sure to stop using `rng` before anyone else // SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference // creates another mutable reference
let rng = unsafe { &mut *self.rng.get() }; let rng = unsafe { &mut *self.rng.get() };
@ -106,7 +110,7 @@ thread_local!(
// We require Rc<..> to avoid premature freeing when thread_rng is used // We require Rc<..> to avoid premature freeing when thread_rng is used
// within thread-local destructors. See #968. // within thread-local destructors. See #968.
static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>> = { static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>> = {
let r = Core::from_rng(OsRng).unwrap_or_else(|err| let r = Core::try_from_os_rng().unwrap_or_else(|err|
panic!("could not initialize thread_rng: {}", err)); panic!("could not initialize thread_rng: {}", err));
let rng = ReseedingRng::new(r, let rng = ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD, THREAD_RNG_RESEED_THRESHOLD,
@ -132,7 +136,10 @@ thread_local!(
/// println!("A simulated die roll: {}", rng.gen_range(1..=6)); /// println!("A simulated die roll: {}", rng.gen_range(1..=6));
/// # } /// # }
/// ``` /// ```
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))))] #[cfg_attr(
doc_cfg,
doc(cfg(all(feature = "std", feature = "std_rng", feature = "getrandom")))
)]
pub fn thread_rng() -> ThreadRng { pub fn thread_rng() -> ThreadRng {
let rng = THREAD_RNG_KEY.with(|t| t.clone()); let rng = THREAD_RNG_KEY.with(|t| t.clone());
ThreadRng { rng } ThreadRng { rng }
@ -161,23 +168,18 @@ impl RngCore for ThreadRng {
rng.next_u64() rng.next_u64()
} }
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
// SAFETY: We must make sure to stop using `rng` before anyone else // SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference // creates another mutable reference
let rng = unsafe { &mut *self.rng.get() }; let rng = unsafe { &mut *self.rng.get() };
rng.fill_bytes(dest) rng.fill_bytes(dest)
} }
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
// SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference
let rng = unsafe { &mut *self.rng.get() };
rng.try_fill_bytes(dest)
}
} }
impl CryptoRng for ThreadRng {} impl CryptoRng for ThreadRng {}
rand_core::impl_try_crypto_rng_from_crypto_rng!(ThreadRng);
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -193,6 +195,9 @@ mod test {
fn test_debug_output() { fn test_debug_output() {
// We don't care about the exact output here, but it must not include // We don't care about the exact output here, but it must not include
// private CSPRNG state or the cache stored by BlockRng! // private CSPRNG state or the cache stored by BlockRng!
assert_eq!(std::format!("{:?}", crate::thread_rng()), "ThreadRng { .. }"); assert_eq!(
std::format!("{:?}", crate::thread_rng()),
"ThreadRng { .. }"
);
} }
} }

View File

@ -6,10 +6,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; use rand_core::impls::{fill_bytes_via_next, next_u64_via_u32};
use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next};
use rand_core::le::read_u32_into; use rand_core::le::read_u32_into;
use rand_core::{SeedableRng, RngCore, Error}; use rand_core::{RngCore, SeedableRng};
#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
/// A xoshiro128++ random number generator. /// A xoshiro128++ random number generator.
/// ///
@ -20,7 +20,7 @@ use rand_core::{SeedableRng, RngCore, Error};
/// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by /// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by
/// David Blackman and Sebastiano Vigna. /// David Blackman and Sebastiano Vigna.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Xoshiro128PlusPlus { pub struct Xoshiro128PlusPlus {
s: [u32; 4], s: [u32; 4],
} }
@ -61,7 +61,7 @@ impl SeedableRng for Xoshiro128PlusPlus {
impl RngCore for Xoshiro128PlusPlus { impl RngCore for Xoshiro128PlusPlus {
#[inline] #[inline]
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
let result_starstar = self.s[0] let res = self.s[0]
.wrapping_add(self.s[3]) .wrapping_add(self.s[3])
.rotate_left(7) .rotate_left(7)
.wrapping_add(self.s[0]); .wrapping_add(self.s[0]);
@ -77,7 +77,7 @@ impl RngCore for Xoshiro128PlusPlus {
self.s[3] = self.s[3].rotate_left(11); self.s[3] = self.s[3].rotate_left(11);
result_starstar res
} }
#[inline] #[inline]
@ -86,30 +86,27 @@ impl RngCore for Xoshiro128PlusPlus {
} }
#[inline] #[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dst: &mut [u8]) {
fill_bytes_via_next(self, dest); fill_bytes_via_next(self, dst)
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
} }
} }
rand_core::impl_try_rng_from_rng_core!(Xoshiro128PlusPlus);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::Xoshiro128PlusPlus;
use rand_core::{RngCore, SeedableRng};
#[test] #[test]
fn reference() { fn reference() {
let mut rng = Xoshiro128PlusPlus::from_seed( let mut rng =
[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]); Xoshiro128PlusPlus::from_seed([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
// These values were produced with the reference implementation: // These values were produced with the reference implementation:
// http://xoshiro.di.unimi.it/xoshiro128plusplus.c // http://xoshiro.di.unimi.it/xoshiro128plusplus.c
let expected = [ let expected = [
641, 1573767, 3222811527, 3517856514, 836907274, 4247214768, 641, 1573767, 3222811527, 3517856514, 836907274, 4247214768, 3867114732, 1355841295,
3867114732, 1355841295, 495546011, 621204420, 495546011, 621204420,
]; ];
for &e in &expected { for &e in &expected {
assert_eq!(rng.next_u32(), e); assert_eq!(rng.next_u32(), e);

View File

@ -6,10 +6,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
use rand_core::impls::fill_bytes_via_next; use rand_core::impls::fill_bytes_via_next;
use rand_core::le::read_u64_into; use rand_core::le::read_u64_into;
use rand_core::{SeedableRng, RngCore, Error}; use rand_core::{RngCore, SeedableRng};
#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
/// A xoshiro256++ random number generator. /// A xoshiro256++ random number generator.
/// ///
@ -20,7 +20,7 @@ use rand_core::{SeedableRng, RngCore, Error};
/// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by /// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by
/// David Blackman and Sebastiano Vigna. /// David Blackman and Sebastiano Vigna.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Xoshiro256PlusPlus { pub struct Xoshiro256PlusPlus {
s: [u64; 4], s: [u64; 4],
} }
@ -63,12 +63,13 @@ impl RngCore for Xoshiro256PlusPlus {
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
// The lowest bits have some linear dependencies, so we use the // The lowest bits have some linear dependencies, so we use the
// upper bits instead. // upper bits instead.
(self.next_u64() >> 32) as u32 let val = self.next_u64();
(val >> 32) as u32
} }
#[inline] #[inline]
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
let result_plusplus = self.s[0] let res = self.s[0]
.wrapping_add(self.s[3]) .wrapping_add(self.s[3])
.rotate_left(23) .rotate_left(23)
.wrapping_add(self.s[0]); .wrapping_add(self.s[0]);
@ -84,36 +85,41 @@ impl RngCore for Xoshiro256PlusPlus {
self.s[3] = self.s[3].rotate_left(45); self.s[3] = self.s[3].rotate_left(45);
result_plusplus res
} }
#[inline] #[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dst: &mut [u8]) {
fill_bytes_via_next(self, dest); fill_bytes_via_next(self, dst)
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
} }
} }
rand_core::impl_try_rng_from_rng_core!(Xoshiro256PlusPlus);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::Xoshiro256PlusPlus;
use rand_core::{RngCore, SeedableRng};
#[test] #[test]
fn reference() { fn reference() {
let mut rng = Xoshiro256PlusPlus::from_seed( let mut rng = Xoshiro256PlusPlus::from_seed([
[1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]); 0, 0, 0,
]);
// These values were produced with the reference implementation: // These values were produced with the reference implementation:
// http://xoshiro.di.unimi.it/xoshiro256plusplus.c // http://xoshiro.di.unimi.it/xoshiro256plusplus.c
let expected = [ let expected = [
41943041, 58720359, 3588806011781223, 3591011842654386, 41943041,
9228616714210784205, 9973669472204895162, 14011001112246962877, 58720359,
12406186145184390807, 15849039046786891736, 10450023813501588000, 3588806011781223,
3591011842654386,
9228616714210784205,
9973669472204895162,
14011001112246962877,
12406186145184390807,
15849039046786891736,
10450023813501588000,
]; ];
for &e in &expected { for &e in &expected {
assert_eq!(rng.next_u64(), e); assert_eq!(rng.next_u64(), e);