From fba5521f0f0f085e6e414562b762b5bf514ed9df Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 8 May 2024 16:10:32 +0300 Subject: [PATCH] Add `TryRngCore` and `TryCryptoRng` traits (#1424) This reworks fallibility, replacing the fixed `Error` type. --- README.md | 2 +- benches/benches/base_distributions.rs | 22 +-- benches/benches/generators.rs | 65 +++---- benches/benches/misc.rs | 28 +-- benches/benches/seq.rs | 14 +- benches/src/distributions.rs | 21 +-- benches/src/uniform.rs | 8 +- benches/src/uniform_float.rs | 12 +- rand_chacha/README.md | 2 +- rand_chacha/src/chacha.rs | 91 +++++----- rand_core/src/blanket_impls.rs | 91 ++++++++++ rand_core/src/block.rs | 73 ++++---- rand_core/src/error.rs | 226 ------------------------ rand_core/src/impls.rs | 52 +++++- rand_core/src/lib.rs | 244 ++++++++++++++------------ rand_core/src/os.rs | 44 ++--- rand_distr/tests/uniformity.rs | 4 +- rand_pcg/src/lib.rs | 2 +- rand_pcg/src/pcg128.rs | 14 +- rand_pcg/src/pcg128cm.rs | 12 +- rand_pcg/src/pcg64.rs | 8 +- rand_pcg/tests/lcg128cmdxsm64.rs | 2 +- rand_pcg/tests/lcg128xsl64.rs | 2 +- rand_pcg/tests/lcg64xsh32.rs | 2 +- rand_pcg/tests/mcg128xsl64.rs | 2 +- src/distributions/distribution.rs | 9 +- src/distributions/mod.rs | 2 +- src/lib.rs | 9 +- src/prelude.rs | 5 +- src/rng.rs | 86 ++++----- src/rngs/mock.rs | 30 ++-- src/rngs/mod.rs | 17 +- src/rngs/reseeding.rs | 45 +++-- src/rngs/small.rs | 15 +- src/rngs/std.rs | 21 +-- src/rngs/thread.rs | 35 ++-- src/rngs/xoshiro128plusplus.rs | 35 ++-- src/rngs/xoshiro256plusplus.rs | 48 ++--- 38 files changed, 641 insertions(+), 759 deletions(-) create mode 100644 rand_core/src/blanket_impls.rs delete mode 100644 rand_core/src/error.rs diff --git a/README.md b/README.md index ab080dfc05..9fa7a2f852 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ compiler versions will be compatible. This is especially true of Rand's experimental `simd_support` feature. 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 `alloc` is enabled), and `thread_rng` and `random` are unavailable. diff --git a/benches/benches/base_distributions.rs b/benches/benches/base_distributions.rs index 6b6bd39735..c60ce47aea 100644 --- a/benches/benches/base_distributions.rs +++ b/benches/benches/base_distributions.rs @@ -32,7 +32,7 @@ macro_rules! distr_int { ($fnn:ident, $ty:ty, $distr:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; b.iter(|| { @@ -52,7 +52,7 @@ macro_rules! distr_nz_int { ($fnn:ident, $tynz:ty, $ty:ty, $distr:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; b.iter(|| { @@ -72,7 +72,7 @@ macro_rules! distr_float { ($fnn:ident, $ty:ty, $distr:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; b.iter(|| { @@ -92,7 +92,7 @@ macro_rules! distr_duration { ($fnn:ident, $distr:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; b.iter(|| { @@ -114,7 +114,7 @@ macro_rules! distr { ($fnn:ident, $ty:ty, $distr:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; b.iter(|| { @@ -191,7 +191,7 @@ macro_rules! gen_range_int { ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); b.iter(|| { let mut high = $high; @@ -199,7 +199,7 @@ macro_rules! gen_range_int { for _ in 0..RAND_BENCH_N { accum = accum.wrapping_add(rng.gen_range($low..high)); // force recalculation of range each time - high = high.wrapping_add(1) & core::$ty::MAX; + high = high.wrapping_add(1) & $ty::MAX; } accum }); @@ -230,7 +230,7 @@ macro_rules! gen_range_float { ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); b.iter(|| { let mut high = $high; @@ -267,7 +267,7 @@ macro_rules! uniform_sample { ($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let low = black_box($low); let high = black_box($high); b.iter(|| { @@ -286,7 +286,7 @@ macro_rules! uniform_inclusive { ($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let low = black_box($low); let high = black_box($high); b.iter(|| { @@ -306,7 +306,7 @@ macro_rules! uniform_single { ($fnn:ident, $type:ident, $low:expr, $high:expr, $count:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let low = black_box($low); let high = black_box($high); b.iter(|| { diff --git a/benches/benches/generators.rs b/benches/benches/generators.rs index 9d3012fccb..05090c2449 100644 --- a/benches/benches/generators.rs +++ b/benches/benches/generators.rs @@ -15,13 +15,14 @@ const RAND_BENCH_N: u64 = 1000; const BYTES_LEN: usize = 1024; use core::mem::size_of; +use rand_chacha::rand_core::UnwrapErr; use test::{black_box, Bencher}; use rand::prelude::*; use rand::rngs::ReseedingRng; use rand::rngs::{mock::StepRng, OsRng}; 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 { ($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_pcg32, Pcg32::from_entropy()); -gen_bytes!(gen_bytes_pcg64, Pcg64::from_entropy()); -gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_entropy()); -gen_bytes!(gen_bytes_pcg64dxsm, Pcg64Dxsm::from_entropy()); -gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_entropy()); -gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy()); -gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy()); -gen_bytes!(gen_bytes_std, StdRng::from_entropy()); +gen_bytes!(gen_bytes_pcg32, Pcg32::from_os_rng()); +gen_bytes!(gen_bytes_pcg64, Pcg64::from_os_rng()); +gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_os_rng()); +gen_bytes!(gen_bytes_pcg64dxsm, Pcg64Dxsm::from_os_rng()); +gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_os_rng()); +gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_os_rng()); +gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_os_rng()); +gen_bytes!(gen_bytes_std, StdRng::from_os_rng()); #[cfg(feature = "small_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()); macro_rules! gen_uint { @@ -62,7 +63,7 @@ macro_rules! gen_uint { b.iter(|| { let mut accum: $ty = 0; for _ in 0..RAND_BENCH_N { - accum = accum.wrapping_add(rng.gen::<$ty>()); + accum = accum.wrapping_add(rng.random::<$ty>()); } accum }); @@ -72,40 +73,40 @@ macro_rules! gen_uint { } gen_uint!(gen_u32_step, u32, StepRng::new(0, 1)); -gen_uint!(gen_u32_pcg32, u32, Pcg32::from_entropy()); -gen_uint!(gen_u32_pcg64, u32, Pcg64::from_entropy()); -gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_entropy()); -gen_uint!(gen_u32_pcg64dxsm, u32, Pcg64Dxsm::from_entropy()); -gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_entropy()); -gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_entropy()); -gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_entropy()); -gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); +gen_uint!(gen_u32_pcg32, u32, Pcg32::from_os_rng()); +gen_uint!(gen_u32_pcg64, u32, Pcg64::from_os_rng()); +gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_os_rng()); +gen_uint!(gen_u32_pcg64dxsm, u32, Pcg64Dxsm::from_os_rng()); +gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_os_rng()); +gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_os_rng()); +gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_os_rng()); +gen_uint!(gen_u32_std, u32, StdRng::from_os_rng()); #[cfg(feature = "small_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_u64_step, u64, StepRng::new(0, 1)); -gen_uint!(gen_u64_pcg32, u64, Pcg32::from_entropy()); -gen_uint!(gen_u64_pcg64, u64, Pcg64::from_entropy()); -gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_entropy()); -gen_uint!(gen_u64_pcg64dxsm, u64, Pcg64Dxsm::from_entropy()); -gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_entropy()); -gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_entropy()); -gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_entropy()); -gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); +gen_uint!(gen_u64_pcg32, u64, Pcg32::from_os_rng()); +gen_uint!(gen_u64_pcg64, u64, Pcg64::from_os_rng()); +gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_os_rng()); +gen_uint!(gen_u64_pcg64dxsm, u64, Pcg64Dxsm::from_os_rng()); +gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_os_rng()); +gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_os_rng()); +gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_os_rng()); +gen_uint!(gen_u64_std, u64, StdRng::from_os_rng()); #[cfg(feature = "small_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()); macro_rules! init_gen { ($fnn:ident, $gen:ident) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng = Pcg32::from_entropy(); + let mut rng = Pcg32::from_os_rng(); b.iter(|| { - let r2 = $gen::from_rng(&mut rng).unwrap(); + let r2 = $gen::from_rng(&mut rng); r2 }); } @@ -125,7 +126,7 @@ macro_rules! reseeding_bytes { ($fnn:ident, $thresh:expr) => { #[bench] 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]; b.iter(|| { for _ in 0..RESEEDING_BENCH_N { diff --git a/benches/benches/misc.rs b/benches/benches/misc.rs index a3c353bbdd..50dfc0ea8a 100644 --- a/benches/benches/misc.rs +++ b/benches/benches/misc.rs @@ -20,7 +20,7 @@ use rand_pcg::{Pcg32, Pcg64Mcg}; #[bench] 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(|| { let mut accum = true; for _ in 0..RAND_BENCH_N { @@ -32,7 +32,7 @@ fn misc_gen_bool_const(b: &mut Bencher) { #[bench] 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(|| { let mut accum = true; let mut p = 0.18; @@ -46,7 +46,7 @@ fn misc_gen_bool_var(b: &mut Bencher) { #[bench] 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(|| { let mut accum = true; for _ in 0..RAND_BENCH_N { @@ -58,7 +58,7 @@ fn misc_gen_ratio_const(b: &mut Bencher) { #[bench] 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(|| { let mut accum = true; for i in 2..(RAND_BENCH_N as u32 + 2) { @@ -70,7 +70,7 @@ fn misc_gen_ratio_var(b: &mut Bencher) { #[bench] 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(|| { let d = Bernoulli::new(0.18).unwrap(); let mut accum = true; @@ -83,7 +83,7 @@ fn misc_bernoulli_const(b: &mut Bencher) { #[bench] 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(|| { let mut accum = true; let mut p = 0.18; @@ -99,7 +99,7 @@ fn misc_bernoulli_var(b: &mut Bencher) { #[bench] fn gen_1kb_u16_iter_repeat(b: &mut Bencher) { use core::iter; - let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); + let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()); b.iter(|| { let v: Vec = iter::repeat(()).map(|()| rng.random()).take(512).collect(); v @@ -109,7 +109,7 @@ fn gen_1kb_u16_iter_repeat(b: &mut Bencher) { #[bench] 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(|| { let v: Vec = Standard.sample_iter(&mut rng).take(512).collect(); v @@ -119,7 +119,7 @@ fn gen_1kb_u16_sample_iter(b: &mut Bencher) { #[bench] 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(|| { // max supported array length is 32! let v: [[u16; 32]; 16] = rng.random(); @@ -130,7 +130,7 @@ fn gen_1kb_u16_gen_array(b: &mut Bencher) { #[bench] 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]; b.iter(|| { rng.fill(&mut buf[..]); @@ -142,7 +142,7 @@ fn gen_1kb_u16_fill(b: &mut Bencher) { #[bench] fn gen_1kb_u64_iter_repeat(b: &mut Bencher) { use core::iter; - let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); + let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()); b.iter(|| { let v: Vec = iter::repeat(()).map(|()| rng.random()).take(128).collect(); v @@ -152,7 +152,7 @@ fn gen_1kb_u64_iter_repeat(b: &mut Bencher) { #[bench] 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(|| { let v: Vec = Standard.sample_iter(&mut rng).take(128).collect(); v @@ -162,7 +162,7 @@ fn gen_1kb_u64_sample_iter(b: &mut Bencher) { #[bench] 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(|| { // max supported array length is 32! let v: [[u64; 32]; 4] = rng.random(); @@ -173,7 +173,7 @@ fn gen_1kb_u64_gen_array(b: &mut Bencher) { #[bench] 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]; b.iter(|| { rng.fill(&mut buf[..]); diff --git a/benches/benches/seq.rs b/benches/benches/seq.rs index bcc1e7c20e..8b4b774b02 100644 --- a/benches/benches/seq.rs +++ b/benches/benches/seq.rs @@ -25,7 +25,7 @@ const RAND_BENCH_N: u64 = 1000; #[bench] 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]; b.iter(|| { x.shuffle(&mut rng); @@ -35,7 +35,7 @@ fn seq_shuffle_100(b: &mut Bencher) { #[bench] 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]; for (i, r) in x.iter_mut().enumerate() { *r = i; @@ -54,7 +54,7 @@ macro_rules! seq_slice_choose_multiple { ($name:ident, $amount:expr, $length:expr) => { #[bench] 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 mut result = [0i32; $amount]; b.iter(|| { @@ -76,14 +76,14 @@ seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100); #[bench] 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]; b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10)) } #[bench] 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 mut buf = [0; 10]; 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) => { #[bench] 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)) } }; @@ -112,7 +112,7 @@ macro_rules! sample_indices_rand_weights { ($name:ident, $amount:expr, $length:expr) => { #[bench] 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::sample_weighted(&mut rng, $length, |idx| (1 + (idx % 100)) as u32, $amount) }) diff --git a/benches/src/distributions.rs b/benches/src/distributions.rs index 2677fca481..37b0c8d272 100644 --- a/benches/src/distributions.rs +++ b/benches/src/distributions.rs @@ -30,7 +30,7 @@ macro_rules! distr_int { $group.throughput(Throughput::Bytes( size_of::<$ty>() as u64 * RAND_BENCH_N)); $group.bench_function($fnn, |c| { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; c.iter(|| { @@ -50,7 +50,7 @@ macro_rules! distr_float { $group.throughput(Throughput::Bytes( size_of::<$ty>() as u64 * RAND_BENCH_N)); $group.bench_function($fnn, |c| { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; c.iter(|| { @@ -70,7 +70,7 @@ macro_rules! distr { $group.throughput(Throughput::Bytes( size_of::<$ty>() as u64 * RAND_BENCH_N)); $group.bench_function($fnn, |c| { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; c.iter(|| { @@ -90,7 +90,7 @@ macro_rules! distr_arr { $group.throughput(Throughput::Bytes( size_of::<$ty>() as u64 * RAND_BENCH_N)); $group.bench_function($fnn, |c| { - let mut rng = Pcg64Mcg::from_entropy(); + let mut rng = Pcg64Mcg::from_os_rng(); let distr = $distr; c.iter(|| { @@ -127,8 +127,9 @@ fn bench(c: &mut Criterion) { distr_float!(g, "log_normal", f64, LogNormal::new(-1.23, 4.56).unwrap()); g.throughput(Throughput::Bytes(size_of::() as u64 * RAND_BENCH_N)); g.bench_function("iter", |c| { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = Normal::new(-2.71828, 3.14159).unwrap(); + use core::f64::consts::{E, PI}; + let mut rng = Pcg64Mcg::from_os_rng(); + let distr = Normal::new(-E, PI).unwrap(); let mut iter = distr.sample_iter(&mut rng); c.iter(|| { @@ -176,9 +177,9 @@ fn bench(c: &mut Criterion) { { 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_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_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_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_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()); @@ -194,7 +195,7 @@ fn bench(c: &mut Criterion) { sample_binomial!(g, "binomial_10", 10, 0.9); sample_binomial!(g, "binomial_100", 100, 0.99); 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); } { diff --git a/benches/src/uniform.rs b/benches/src/uniform.rs index 0ed0f2cde4..948d131588 100644 --- a/benches/src/uniform.rs +++ b/benches/src/uniform.rs @@ -23,8 +23,8 @@ const N_RESAMPLES: usize = 10_000; macro_rules! sample { ($R:ty, $T:ty, $U:ty, $g:expr) => { $g.bench_function(BenchmarkId::new(stringify!($R), "single"), |b| { - let mut rng = <$R>::from_rng(thread_rng()).unwrap(); - let x = rng.gen::<$U>(); + let mut rng = <$R>::from_rng(thread_rng()); + let x = rng.random::<$U>(); let bits = (<$T>::BITS / 2); let mask = (1 as $U).wrapping_neg() >> bits; let range = (x >> bits) * (x & mask); @@ -35,8 +35,8 @@ macro_rules! sample { }); $g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| { - let mut rng = <$R>::from_rng(thread_rng()).unwrap(); - let x = rng.gen::<$U>(); + let mut rng = <$R>::from_rng(thread_rng()); + let x = rng.random::<$U>(); let bits = (<$T>::BITS / 2); let mask = (1 as $U).wrapping_neg() >> bits; let range = (x >> bits) * (x & mask); diff --git a/benches/src/uniform_float.rs b/benches/src/uniform_float.rs index 957ff1b8ec..91c0eff4b7 100644 --- a/benches/src/uniform_float.rs +++ b/benches/src/uniform_float.rs @@ -27,11 +27,11 @@ const N_RESAMPLES: usize = 10_000; macro_rules! single_random { ($R:ty, $T:ty, $g:expr) => { $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); loop { - low = <$T>::from_bits(rng.gen()); - high = <$T>::from_bits(rng.gen()); + low = <$T>::from_bits(rng.random()); + high = <$T>::from_bits(rng.random()); if (low < high) && (high - low).is_normal() { break; } @@ -63,10 +63,10 @@ fn single_random(c: &mut Criterion) { macro_rules! distr_random { ($R:ty, $T:ty, $g:expr) => { $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 low = <$T>::from_bits(rng.gen()); - let high = <$T>::from_bits(rng.gen()); + let low = <$T>::from_bits(rng.random()); + let high = <$T>::from_bits(rng.random()); if let Ok(dist) = Uniform::<$T>::new_inclusive(low, high) { break dist; } diff --git a/rand_chacha/README.md b/rand_chacha/README.md index 6412538ead..1b555ad086 100644 --- a/rand_chacha/README.md +++ b/rand_chacha/README.md @@ -36,7 +36,7 @@ Links: `rand_chacha` is `no_std` compatible when disabling default features; the `std` feature can be explicitly required to re-enable `std` support. 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 diff --git a/rand_chacha/src/chacha.rs b/rand_chacha/src/chacha.rs index ebc28a8ab0..14be765a18 100644 --- a/rand_chacha/src/chacha.rs +++ b/rand_chacha/src/chacha.rs @@ -14,9 +14,10 @@ use self::core::fmt; use crate::guts::ChaCha; 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 const BUF_BLOCKS: u8 = 4; @@ -68,7 +69,7 @@ impl fmt::Debug for Array64 { } 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] #[derive(Clone, PartialEq, Eq)] pub struct $ChaChaXCore { @@ -85,6 +86,7 @@ macro_rules! chacha_impl { impl BlockRngCore for $ChaChaXCore { type Item = u32; type Results = Array64; + #[inline] fn generate(&mut self, r: &mut Self::Results) { self.state.refill4($rounds, &mut r.0); @@ -93,9 +95,12 @@ macro_rules! chacha_impl { impl SeedableRng for $ChaChaXCore { type Seed = [u8; 32]; + #[inline] 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 { type Seed = [u8; 32]; + #[inline] fn from_seed(seed: Self::Seed) -> Self { let core = $ChaChaXCore::from_seed(seed); @@ -160,18 +166,16 @@ macro_rules! chacha_impl { fn next_u32(&mut self) -> u32 { self.rng.next_u32() } + #[inline] fn next_u64(&mut self) -> u64 { self.rng.next_u64() } + #[inline] fn fill_bytes(&mut self, bytes: &mut [u8]) { 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 { @@ -209,11 +213,9 @@ macro_rules! chacha_impl { #[inline] pub fn set_word_pos(&mut self, word_offset: u128) { let block = (word_offset / u128::from(BLOCK_WORDS)) as u64; + self.rng.core.state.set_block_pos(block); self.rng - .core - .state - .set_block_pos(block); - self.rng.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize); + .generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize); } /// Set the stream number. @@ -229,10 +231,7 @@ macro_rules! chacha_impl { /// indirectly via `set_word_pos`), but this is not directly supported. #[inline] pub fn set_stream(&mut self, stream: u64) { - self.rng - .core - .state - .set_nonce(stream); + self.rng.core.state.set_nonce(stream); if self.rng.index() != 64 { let wp = self.get_word_pos(); self.set_word_pos(wp); @@ -242,24 +241,20 @@ macro_rules! chacha_impl { /// Get the stream number. #[inline] pub fn get_stream(&self) -> u64 { - self.rng - .core - .state - .get_nonce() + self.rng.core.state.get_nonce() } /// Get the seed. #[inline] pub fn get_seed(&self) -> [u8; 32] { - self.rng - .core - .state - .get_seed() + self.rng.core.state.get_seed() } } impl CryptoRng for $ChaChaXRng {} + rand_core::impl_try_crypto_rng_from_crypto_rng!($ChaChaXRng); + impl From<$ChaChaXCore> for $ChaChaXRng { fn from(core: $ChaChaXCore) -> Self { $ChaChaXRng { @@ -286,22 +281,20 @@ macro_rules! chacha_impl { } #[cfg(feature = "serde1")] impl<'de> Deserialize<'de> for $ChaChaXRng { - fn deserialize(d: D) -> Result where D: Deserializer<'de> { + fn deserialize(d: D) -> Result + where D: Deserializer<'de> { $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x)) } } 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 // comparison and serialization of this object is considered a semver-covered part of // the API. #[derive(Debug, PartialEq, Eq)] - #[cfg_attr( - feature = "serde1", - derive(Serialize, Deserialize), - )] + #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub(crate) struct $ChaChaXRng { seed: [u8; 32], stream: u64, @@ -331,18 +324,36 @@ macro_rules! chacha_impl { } } } - } + }; } -chacha_impl!(ChaCha20Core, 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); +chacha_impl!( + ChaCha20Core, + 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)] mod test { 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; @@ -350,8 +361,8 @@ mod test { #[test] fn test_chacha_serde_roundtrip() { 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, - 0, 2, 92, + 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, 0, 2, 92, ]; let mut rng1 = ChaCha20Rng::from_seed(seed); let mut rng2 = ChaCha12Rng::from_seed(seed); @@ -388,7 +399,7 @@ mod test { #[test] 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 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(); assert_eq!(j, j1); } @@ -402,7 +413,7 @@ mod test { let mut rng1 = ChaChaRng::from_seed(seed); 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); } @@ -598,7 +609,7 @@ mod test { #[test] 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()); // 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); diff --git a/rand_core/src/blanket_impls.rs b/rand_core/src/blanket_impls.rs new file mode 100644 index 0000000000..cadd456ca5 --- /dev/null +++ b/rand_core/src/blanket_impls.rs @@ -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 { + R::try_next_u32(self) + } + + #[inline(always)] + fn try_next_u64(&mut self) -> Result { + 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 RngCore for Box { + #[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 CryptoRng for Box {} + +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] +impl TryRngCore for Box { + type Error = R::Error; + + #[inline(always)] + fn try_next_u32(&mut self) -> Result { + R::try_next_u32(self) + } + + #[inline(always)] + fn try_next_u64(&mut self) -> Result { + 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 TryCryptoRng for Box {} diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs index 9122f9bc67..b5cc42bdbe 100644 --- a/rand_core/src/block.rs +++ b/rand_core/src/block.rs @@ -54,10 +54,9 @@ //! [`fill_bytes`]: RngCore::fill_bytes 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; -#[cfg(feature = "serde1")] -use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize}; /// A trait for RNGs which do not generate random numbers individually, but in /// blocks (typically `[u32; N]`). This technique is commonly used by @@ -80,7 +79,7 @@ pub trait BlockRngCore { /// supposed to be cryptographically secure. /// /// See [`CryptoRng`] docs for more information. -pub trait CryptoBlockRng: BlockRngCore { } +pub trait CryptoBlockRng: BlockRngCore {} /// A wrapper type implementing [`RngCore`] for some type implementing /// [`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 /// reading values from the results buffer, as well as /// calling [`BlockRngCore::generate`] directly on the output array when -/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods -/// also handle the bookkeeping of when to generate a new batch of values. +/// [`fill_bytes`] is called on a large array. These methods also handle +/// the bookkeeping of when to generate a new batch of values. /// /// No whole generated `u32` values are thrown away and all values are consumed /// in-order. [`next_u32`] simply takes the next available `u32` value. /// [`next_u64`] is implemented by combining two `u32` values, least -/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole -/// number of `u32` values, converting each `u32` to a byte slice in -/// little-endian order. If the requested byte length is not a multiple of 4, -/// some bytes will be discarded. +/// significant first. [`fill_bytes`] consume a whole number of `u32` values, +/// converting each `u32` to a byte slice in little-endian order. If the requested byte +/// length is not a multiple of 4, some bytes will be discarded. /// /// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is /// no direct support for other buffer types. @@ -116,7 +114,6 @@ pub trait CryptoBlockRng: BlockRngCore { } /// [`next_u32`]: RngCore::next_u32 /// [`next_u64`]: RngCore::next_u64 /// [`fill_bytes`]: RngCore::fill_bytes -/// [`try_fill_bytes`]: RngCore::try_fill_bytes #[derive(Clone)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[cfg_attr( @@ -227,19 +224,15 @@ impl> RngCore for BlockRng { if self.index >= self.results.as_ref().len() { self.generate_and_set(0); } - let (consumed_u32, filled_u8) = - fill_via_u32_chunks(&mut self.results.as_mut()[self.index..], &mut dest[read_len..]); + let (consumed_u32, filled_u8) = fill_via_u32_chunks( + &mut self.results.as_mut()[self.index..], + &mut dest[read_len..], + ); self.index += consumed_u32; read_len += filled_u8; } } - - #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } } impl SeedableRng for BlockRng { @@ -256,8 +249,13 @@ impl SeedableRng for BlockRng { } #[inline(always)] - fn from_rng(rng: S) -> Result { - Ok(Self::new(R::from_rng(rng)?)) + fn from_rng(rng: impl RngCore) -> Self { + Self::new(R::from_rng(rng)) + } + + #[inline(always)] + fn try_from_rng(rng: S) -> Result { + R::try_from_rng(rng).map(Self::new) } } @@ -277,14 +275,12 @@ impl> CryptoRng for BlockRng {} /// 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`] and [`try_fill_bytes`] consume a whole number of `u64` -/// values. If the requested length is not a multiple of 8, some bytes will be -/// discarded. +/// [`fill_bytes`] `] consume a whole number of `u64` values. If the requested length +/// is not a multiple of 8, some bytes will be discarded. /// /// [`next_u32`]: RngCore::next_u32 /// [`next_u64`]: RngCore::next_u64 /// [`fill_bytes`]: RngCore::fill_bytes -/// [`try_fill_bytes`]: RngCore::try_fill_bytes #[derive(Clone)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct BlockRng64 { @@ -402,12 +398,6 @@ impl> RngCore for BlockRng64 { read_len += filled_u8; } } - - #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } } impl SeedableRng for BlockRng64 { @@ -424,8 +414,13 @@ impl SeedableRng for BlockRng64 { } #[inline(always)] - fn from_rng(rng: S) -> Result { - Ok(Self::new(R::from_rng(rng)?)) + fn from_rng(rng: impl RngCore) -> Self { + Self::new(R::from_rng(rng)) + } + + #[inline(always)] + fn try_from_rng(rng: S) -> Result { + R::try_from_rng(rng).map(Self::new) } } @@ -433,8 +428,8 @@ impl> CryptoRng for BlockRng64 { #[cfg(test)] mod test { - use crate::{SeedableRng, RngCore}; use crate::block::{BlockRng, BlockRng64, BlockRngCore}; + use crate::{RngCore, SeedableRng}; #[derive(Debug, Clone)] struct DummyRng { @@ -443,7 +438,6 @@ mod test { impl BlockRngCore for DummyRng { type Item = u32; - type Results = [u32; 16]; fn generate(&mut self, results: &mut Self::Results) { @@ -458,7 +452,9 @@ mod test { type Seed = [u8; 4]; 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 { type Item = u64; - type Results = [u64; 8]; fn generate(&mut self, results: &mut Self::Results) { @@ -508,7 +503,9 @@ mod test { type Seed = [u8; 8]; fn from_seed(seed: Self::Seed) -> Self { - DummyRng64 { counter: u64::from_le_bytes(seed) } + DummyRng64 { + counter: u64::from_le_bytes(seed), + } } } diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs deleted file mode 100644 index 1a5092fe82..0000000000 --- a/rand_core/src/error.rs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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, - #[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`, which is available with and without `std`. - #[cfg(feature = "std")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] - #[inline] - pub fn new(err: E) -> Self - where E: Into> { - 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 { - 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 { - #[cfg(feature = "std")] - { - if let Some(e) = self.inner.downcast_ref::() { - 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`, 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 { - #[cfg(feature = "std")] - { - self.inner.downcast_ref::().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 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 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 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); - } -} diff --git a/rand_core/src/impls.rs b/rand_core/src/impls.rs index d7dcd3457d..f9152fb273 100644 --- a/rand_core/src/impls.rs +++ b/rand_core/src/impls.rs @@ -74,7 +74,7 @@ impl Observable for u64 { /// unaltered. fn fill_via_chunks(src: &mut [T], dest: &mut [u8]) -> (usize, usize) { let size = core::mem::size_of::(); - 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; // Byte-swap for portability of results. This must happen before copying @@ -160,6 +160,56 @@ pub fn next_u64_via_fill(rng: &mut R) -> u64 { 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`, 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 { + Ok($crate::RngCore::next_u32(self)) + } + + #[inline] + fn try_next_u64(&mut self) -> Result { + 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`, 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() {} + check_crypto_rng_impl::<$t>(); + }; + }; +} + #[cfg(test)] mod test { use super::*; diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 6617ea1c80..07e2b4b5c0 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -19,9 +19,6 @@ //! [`SeedableRng`] is an extension trait for construction from fixed seeds and //! 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 //! implementation of [`RngCore`]. //! @@ -40,18 +37,18 @@ #[cfg(feature = "alloc")] extern crate alloc; #[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; -mod error; pub mod impls; pub mod le; #[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. /// @@ -68,11 +65,6 @@ pub mod le; /// [`next_u32`] and [`next_u64`] methods, implementations may discard some /// 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 /// returning the same value, or never setting certain bits) can break rejection /// 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 /// [`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: /// /// - `Debug` with a custom implementation which *does not* print any internal @@ -107,7 +103,7 @@ pub mod le; /// /// ``` /// #![allow(dead_code)] -/// use rand_core::{RngCore, Error, impls}; +/// use rand_core::{RngCore, impls}; /// /// struct CountingRng(u64); /// @@ -121,21 +117,19 @@ pub mod le; /// self.0 /// } /// -/// fn fill_bytes(&mut self, dest: &mut [u8]) { -/// impls::fill_bytes_via_next(self, dest) -/// } -/// -/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { -/// Ok(self.fill_bytes(dest)) +/// fn fill_bytes(&mut self, dst: &mut [u8]) { +/// impls::fill_bytes_via_next(self, dst) /// } /// } +/// +/// rand_core::impl_try_rng_from_rng_core!(CountingRng); /// ``` /// /// [`rand`]: https://docs.rs/rand -/// [`try_fill_bytes`]: RngCore::try_fill_bytes /// [`fill_bytes`]: RngCore::fill_bytes /// [`next_u32`]: RngCore::next_u32 /// [`next_u64`]: RngCore::next_u64 +/// [`Infallible`]: core::convert::Infallible pub trait RngCore { /// Return the next random `u32`. /// @@ -155,42 +149,22 @@ pub trait RngCore { /// /// RNGs must implement at least one method from this trait directly. In /// the case this method is not implemented directly, it can be implemented - /// via [`impls::fill_bytes_via_next`] or - /// 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). + /// via [`impls::fill_bytes_via_next`]. /// /// This method should guarantee that `dest` is entirely filled /// 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 /// source of randomness). - fn fill_bytes(&mut self, dest: &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 } - } + fn fill_bytes(&mut self, dst: &mut [u8]); } /// A marker trait used to indicate that an [`RngCore`] implementation is /// 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 /// satisfy an additional properties over other generators: given the first /// *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. /// /// [`BlockRngCore`]: block::BlockRngCore +/// [`Infallible`]: core::convert::Infallible 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; + /// Return the next random `u64`. + fn try_next_u64(&mut self) -> Result; + /// 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 + 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(pub R); + +impl RngCore for UnwrapErr { + 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 CryptoRng for UnwrapErr {} + /// A random number generator that can be explicitly seeded. /// /// This trait encapsulates the low-level functionality common to all @@ -339,7 +379,7 @@ pub trait SeedableRng: Sized { 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 /// 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). /// /// [`rand`]: https://docs.rs/rand - fn from_rng(mut rng: R) -> Result { + 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(mut rng: R) -> Result { let mut seed = Self::Seed::default(); rng.try_fill_bytes(seed.as_mut())?; Ok(Self::from_seed(seed)) @@ -374,6 +423,9 @@ pub trait SeedableRng: Sized { /// This method is the recommended way to construct non-deterministic PRNGs /// 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 /// issue, one may prefer to seed from a local PRNG, e.g. /// `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. /// /// [`getrandom`]: https://docs.rs/getrandom + /// [`try_from_os_rng`]: SeedableRng::try_from_os_rng #[cfg(feature = "getrandom")] #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))] #[track_caller] - fn from_entropy() -> Self { - let mut seed = Self::Seed::default(); - if let Err(err) = getrandom::getrandom(seed.as_mut()) { - panic!("from_entropy failed: {}", err); + fn from_os_rng() -> Self { + match Self::try_from_os_rng() { + Ok(res) => res, + 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)] - 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) - } -} - -// 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 RngCore for Box { - #[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) + /// Creates a new instance of the RNG seeded via [`getrandom`] without unwrapping + /// potential [`getrandom`] errors. + /// + /// 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. + /// `from_rng(&mut thread_rng()).unwrap()`. + /// + /// [`getrandom`]: https://docs.rs/getrandom + #[cfg(feature = "getrandom")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))] + fn try_from_os_rng() -> Result { + let mut seed = Self::Seed::default(); + getrandom::getrandom(seed.as_mut())?; + let res = Self::from_seed(seed); + Ok(res) } } @@ -453,38 +471,32 @@ impl RngCore for Box { /// ```no_run /// # use std::{io, io::Read}; /// # 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(); /// ``` #[cfg(feature = "std")] -pub struct RngReadAdapter<'a, R: RngCore + ?Sized> { +pub struct RngReadAdapter<'a, R: TryRngCore + ?Sized> { inner: &'a mut R, } #[cfg(feature = "std")] -impl std::io::Read for RngReadAdapter<'_, R> { +impl std::io::Read for RngReadAdapter<'_, R> { fn read(&mut self, buf: &mut [u8]) -> Result { - 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()) } } #[cfg(feature = "std")] -impl std::fmt::Debug for RngReadAdapter<'_, R> { +impl std::fmt::Debug for RngReadAdapter<'_, R> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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 CryptoRng for Box {} - #[cfg(test)] mod test { use super::*; diff --git a/rand_core/src/os.rs b/rand_core/src/os.rs index b43c9fdaf0..7d0a8ce0ad 100644 --- a/rand_core/src/os.rs +++ b/rand_core/src/os.rs @@ -8,7 +8,7 @@ //! Interface to the random number generator of the operating system. -use crate::{impls, CryptoRng, Error, RngCore}; +use crate::{TryCryptoRng, TryRngCore}; use getrandom::getrandom; /// A random number generator that retrieves randomness from the @@ -36,11 +36,11 @@ use getrandom::getrandom; /// /// # Usage example /// ``` -/// use rand_core::{RngCore, OsRng}; +/// use rand_core::{TryRngCore, OsRng}; /// /// let mut key = [0u8; 16]; -/// OsRng.fill_bytes(&mut key); -/// let random_u64 = OsRng.next_u64(); +/// OsRng.try_fill_bytes(&mut key).unwrap(); +/// let random_u64 = OsRng.try_next_u64().unwrap(); /// ``` /// /// [getrandom]: https://crates.io/crates/getrandom @@ -48,39 +48,41 @@ use getrandom::getrandom; #[derive(Clone, Copy, Debug, Default)] pub struct OsRng; -impl CryptoRng for OsRng {} +impl TryRngCore for OsRng { + type Error = getrandom::Error; -impl RngCore for OsRng { - fn next_u32(&mut self) -> u32 { - impls::next_u32_via_fill(self) + #[inline] + fn try_next_u32(&mut self) -> Result { + let mut buf = [0u8; 4]; + getrandom(&mut buf)?; + Ok(u32::from_ne_bytes(buf)) } - fn next_u64(&mut self) -> u64 { - impls::next_u64_via_fill(self) + #[inline] + fn try_next_u64(&mut self) -> Result { + let mut buf = [0u8; 8]; + getrandom(&mut buf)?; + Ok(u64::from_ne_bytes(buf)) } - fn fill_bytes(&mut self, dest: &mut [u8]) { - if let Err(e) = self.try_fill_bytes(dest) { - panic!("Error: {}", e); - } - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> { getrandom(dest)?; Ok(()) } } +impl TryCryptoRng for OsRng {} + #[test] fn test_os_rng() { - let x = OsRng.next_u64(); - let y = OsRng.next_u64(); + let x = OsRng.try_next_u64().unwrap(); + let y = OsRng.try_next_u64().unwrap(); assert!(x != 0); assert!(x != y); } #[test] fn test_construction() { - let mut rng = OsRng::default(); - assert!(rng.next_u64() != 0); + assert!(OsRng.try_next_u64().unwrap() != 0); } diff --git a/rand_distr/tests/uniformity.rs b/rand_distr/tests/uniformity.rs index d37ef0a9d0..4818eac990 100644 --- a/rand_distr/tests/uniformity.rs +++ b/rand_distr/tests/uniformity.rs @@ -23,7 +23,7 @@ fn unit_sphere() { let h = Histogram100::with_const_width(-1., 1.); let mut histograms = [h.clone(), h.clone(), h]; 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 { let v: [f64; 3] = dist.sample(&mut rng); for i in 0..N_DIM { @@ -51,7 +51,7 @@ fn unit_circle() { use core::f64::consts::PI; let mut h = Histogram100::with_const_width(-PI, PI); 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 { let v: [f64; 2] = dist.sample(&mut rng); h.add(v[0].atan2(v[1])).unwrap(); diff --git a/rand_pcg/src/lib.rs b/rand_pcg/src/lib.rs index e67728a90e..72e6858683 100644 --- a/rand_pcg/src/lib.rs +++ b/rand_pcg/src/lib.rs @@ -47,7 +47,7 @@ //! use rand::{Rng, SeedableRng}; //! use rand_pcg::Pcg64Mcg; //! -//! let mut rng = Pcg64Mcg::from_entropy(); +//! let mut rng = Pcg64Mcg::from_os_rng(); //! let x: f64 = rng.gen(); //! ``` diff --git a/rand_pcg/src/pcg128.rs b/rand_pcg/src/pcg128.rs index df2025dc44..ecb0e56bc4 100644 --- a/rand_pcg/src/pcg128.rs +++ b/rand_pcg/src/pcg128.rs @@ -14,7 +14,7 @@ const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645; 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}; /// 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]) { 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]) { 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)] diff --git a/rand_pcg/src/pcg128cm.rs b/rand_pcg/src/pcg128cm.rs index 7ac5187e4e..29be17a904 100644 --- a/rand_pcg/src/pcg128cm.rs +++ b/rand_pcg/src/pcg128cm.rs @@ -14,7 +14,7 @@ const MULTIPLIER: u64 = 15750249268501108917; 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}; /// A PCG random number generator (CM DXSM 128/64 (LCG) variant). @@ -148,21 +148,15 @@ impl RngCore for Lcg128CmDxsm64 { #[inline] fn next_u64(&mut self) -> u64 { - let val = output_dxsm(self.state); + let res = output_dxsm(self.state); self.step(); - val + res } #[inline] fn fill_bytes(&mut self, dest: &mut [u8]) { 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)] diff --git a/rand_pcg/src/pcg64.rs b/rand_pcg/src/pcg64.rs index 365f1c0b11..0b6864a42f 100644 --- a/rand_pcg/src/pcg64.rs +++ b/rand_pcg/src/pcg64.rs @@ -11,7 +11,7 @@ //! PCG random number generators 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}; // 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]) { impls::fill_bytes_via_next(self, dest) } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } } diff --git a/rand_pcg/tests/lcg128cmdxsm64.rs b/rand_pcg/tests/lcg128cmdxsm64.rs index b254b4fac6..d5f3a6a498 100644 --- a/rand_pcg/tests/lcg128cmdxsm64.rs +++ b/rand_pcg/tests/lcg128cmdxsm64.rs @@ -23,7 +23,7 @@ fn test_lcg128cmdxsm64_construction() { let mut rng1 = Lcg128CmDxsm64::from_seed(seed); 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); let mut rng3 = Lcg128CmDxsm64::seed_from_u64(0); diff --git a/rand_pcg/tests/lcg128xsl64.rs b/rand_pcg/tests/lcg128xsl64.rs index 31eada442e..92c9a41f57 100644 --- a/rand_pcg/tests/lcg128xsl64.rs +++ b/rand_pcg/tests/lcg128xsl64.rs @@ -23,7 +23,7 @@ fn test_lcg128xsl64_construction() { let mut rng1 = Lcg128Xsl64::from_seed(seed); 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); let mut rng3 = Lcg128Xsl64::seed_from_u64(0); diff --git a/rand_pcg/tests/lcg64xsh32.rs b/rand_pcg/tests/lcg64xsh32.rs index 9c181ee3a4..ee884706fb 100644 --- a/rand_pcg/tests/lcg64xsh32.rs +++ b/rand_pcg/tests/lcg64xsh32.rs @@ -21,7 +21,7 @@ fn test_lcg64xsh32_construction() { let mut rng1 = Lcg64Xsh32::from_seed(seed); 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); let mut rng3 = Lcg64Xsh32::seed_from_u64(0); diff --git a/rand_pcg/tests/mcg128xsl64.rs b/rand_pcg/tests/mcg128xsl64.rs index 1f352b6e87..bee87aeb3f 100644 --- a/rand_pcg/tests/mcg128xsl64.rs +++ b/rand_pcg/tests/mcg128xsl64.rs @@ -21,7 +21,7 @@ fn test_mcg128xsl64_construction() { let mut rng1 = Mcg128Xsl64::from_seed(seed); 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); let mut rng3 = Mcg128Xsl64::seed_from_u64(0); diff --git a/src/distributions/distribution.rs b/src/distributions/distribution.rs index a69fa08510..0eabfb8059 100644 --- a/src/distributions/distribution.rs +++ b/src/distributions/distribution.rs @@ -10,9 +10,8 @@ //! Distribution trait and associates use crate::Rng; +#[cfg(feature = "alloc")] use alloc::string::String; use core::iter; -#[cfg(feature = "alloc")] -use alloc::string::String; /// Types (distributions) that can be used to create a random instance of `T`. /// @@ -229,9 +228,7 @@ mod tests { #[test] fn test_make_an_iter() { - fn ten_dice_rolls_other_than_five( - rng: &mut R, - ) -> impl Iterator + '_ { + fn ten_dice_rolls_other_than_five(rng: &mut R) -> impl Iterator + '_ { Uniform::new_inclusive(1, 6) .unwrap() .sample_iter(rng) @@ -251,8 +248,8 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test_dist_string() { - use core::str; use crate::distributions::{Alphanumeric, DistString, Standard}; + use core::str; let mut rng = crate::test::rng(213); let s1 = Alphanumeric.sample_string(&mut rng, 20); diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 050e75d98e..9130342887 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -191,7 +191,7 @@ use crate::Rng; /// use rand::prelude::*; /// 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); /// ``` /// diff --git a/src/lib.rs b/src/lib.rs index 5410b16f33..af51387441 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,8 +57,8 @@ clippy::nonminimal_bool )] -#[cfg(feature = "std")] extern crate std; #[cfg(feature = "alloc")] extern crate alloc; +#[cfg(feature = "std")] extern crate std; #[allow(unused)] macro_rules! trace { ($($x:tt)*) => ( @@ -92,7 +92,7 @@ macro_rules! error { ($($x:tt)*) => ( ) } // Re-exports from rand_core -pub use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; +pub use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore}; // Public modules pub mod distributions; @@ -154,7 +154,10 @@ use crate::distributions::{Distribution, Standard}; /// [`Standard`]: distributions::Standard /// [`ThreadRng`]: rngs::ThreadRng #[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] pub fn random() -> T where Standard: Distribution { diff --git a/src/prelude.rs b/src/prelude.rs index 2f9fa4c8ff..87613532f7 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -14,7 +14,7 @@ //! //! ``` //! use rand::prelude::*; -//! # let mut r = StdRng::from_rng(thread_rng()).unwrap(); +//! # let mut r = StdRng::from_rng(thread_rng()); //! # let _: f32 = r.random(); //! ``` @@ -23,7 +23,8 @@ #[doc(no_inline)] pub use crate::rngs::SmallRng; #[cfg(feature = "std_rng")] -#[doc(no_inline)] pub use crate::rngs::StdRng; +#[doc(no_inline)] +pub use crate::rngs::StdRng; #[doc(no_inline)] #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))] pub use crate::rngs::ThreadRng; diff --git a/src/rng.rs b/src/rng.rs index 6c9d4b7eab..129c141796 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -13,7 +13,7 @@ use crate::distributions::uniform::{SampleRange, SampleUniform}; use crate::distributions::{self, Distribution, Standard}; use core::num::Wrapping; use core::{mem, slice}; -use rand_core::{Error, RngCore}; +use rand_core::RngCore; /// An automatically-implemented extension trait on [`RngCore`] providing high-level /// 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 /// this cannot be guaranteed for third-party implementations. /// - /// This is identical to [`try_fill`] except that it panics on error. - /// /// # Example /// /// ``` @@ -236,38 +234,9 @@ pub trait Rng: RngCore { /// ``` /// /// [`fill_bytes`]: RngCore::fill_bytes - /// [`try_fill`]: Rng::try_fill #[track_caller] fn fill(&mut self, dest: &mut T) { - dest.try_fill(self).expect("Rng::fill failed") - } - - /// 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(&mut self, dest: &mut T) -> Result<(), Error> { - dest.try_fill(self) + dest.fill(self) } /// Return a bool with a probability `p` of being true. @@ -335,9 +304,12 @@ pub trait Rng: RngCore { /// Alias for [`Rng::random`]. #[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(&mut self) -> T - where Standard: Distribution { + where Standard: Distribution { self.random() } } @@ -353,18 +325,17 @@ impl Rng for R {} /// [Chapter on Portability](https://rust-random.github.io/book/portability.html)). pub trait Fill { /// Fill self with random data - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error>; + fn fill(&mut self, rng: &mut R); } macro_rules! impl_fill_each { () => {}; ($t:ty) => { impl Fill for [$t] { - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { + fn fill(&mut self, rng: &mut R) { for elt in self.iter_mut() { *elt = rng.random(); } - Ok(()) } } }; @@ -377,8 +348,8 @@ macro_rules! impl_fill_each { impl_fill_each!(bool, char, f32, f64,); impl Fill for [u8] { - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { - rng.try_fill_bytes(self) + fn fill(&mut self, rng: &mut R) { + rng.fill_bytes(self) } } @@ -387,37 +358,35 @@ macro_rules! impl_fill { ($t:ty) => { impl Fill for [$t] { #[inline(never)] // in micro benchmarks, this improves performance - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { + fn fill(&mut self, rng: &mut R) { if self.len() > 0 { - rng.try_fill_bytes(unsafe { + rng.fill_bytes(unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, mem::size_of_val(self) ) - })?; + }); for x in self { *x = x.to_le(); } } - Ok(()) } } impl Fill for [Wrapping<$t>] { #[inline(never)] - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { + fn fill(&mut self, rng: &mut R) { if self.len() > 0 { - rng.try_fill_bytes(unsafe { + rng.fill_bytes(unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, self.len() * mem::size_of::<$t>() ) - })?; + }); for x in self { *x = Wrapping(x.0.to_le()); } } - Ok(()) } } }; @@ -435,8 +404,8 @@ impl_fill!(i8, i16, i32, i64, isize, i128,); impl Fill for [T; N] where [T]: Fill { - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { - self[..].try_fill(rng) + fn fill(&mut self, rng: &mut R) { + <[T] as Fill>::fill(self, rng) } } @@ -543,24 +512,23 @@ mod test { #[test] #[should_panic] + #[allow(clippy::reversed_empty_ranges)] fn test_gen_range_panic_int() { - #![allow(clippy::reversed_empty_ranges)] let mut r = rng(102); r.gen_range(5..-2); } #[test] #[should_panic] + #[allow(clippy::reversed_empty_ranges)] fn test_gen_range_panic_usize() { - #![allow(clippy::reversed_empty_ranges)] let mut r = rng(103); r.gen_range(5..2); } #[test] + #[allow(clippy::bool_assert_comparison)] fn test_gen_bool() { - #![allow(clippy::bool_assert_comparison)] - let mut r = rng(105); for _ in 0..5 { 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] fn test_rng_trait_object() { use crate::distributions::{Distribution, Standard}; diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs index 66705a008c..e186fb7f06 100644 --- a/src/rngs/mock.rs +++ b/src/rngs/mock.rs @@ -8,10 +8,9 @@ //! Mock random number generator -use rand_core::{impls, Error, RngCore}; +use rand_core::{impls, RngCore}; -#[cfg(feature = "serde1")] -use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize}; /// A mock generator yielding very predictable output /// @@ -64,27 +63,22 @@ impl RngCore for StepRng { #[inline] fn next_u64(&mut self) -> u64 { - let result = self.v; + let res = self.v; self.v = self.v.wrapping_add(self.a); - result + res } #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - impls::fill_bytes_via_next(self, dest); - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) + fn fill_bytes(&mut self, dst: &mut [u8]) { + impls::fill_bytes_via_next(self, dst) } } +rand_core::impl_try_rng_from_rng_core!(StepRng); + #[cfg(test)] mod tests { - #[cfg(any(feature = "alloc", feature = "serde1"))] - use super::StepRng; + #[cfg(any(feature = "alloc", feature = "serde1"))] use super::StepRng; #[test] #[cfg(feature = "serde1")] @@ -94,18 +88,16 @@ mod tests { bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap(); assert_eq!(some_rng.v, de_some_rng.v); assert_eq!(some_rng.a, de_some_rng.a); - } #[test] #[cfg(feature = "alloc")] fn test_bool() { - use crate::{Rng, distributions::Standard}; + use crate::{distributions::Standard, Rng}; // If this result ever changes, update doc on StepRng! let rng = StepRng::new(0, 1 << 31); - let result: alloc::vec::Vec = - rng.sample_iter(Standard).take(6).collect(); + let result: alloc::vec::Vec = rng.sample_iter(Standard).take(6).collect(); assert_eq!(&result, &[false, true, false, true, false, true]); } } diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index 9caeb09e02..d357a71566 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -42,7 +42,7 @@ //! - `from_seed` accepts a type specific to the PRNG //! - `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 -//! - `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. //! @@ -102,18 +102,21 @@ pub use reseeding::ReseedingRng; pub mod mock; // Public so we don't export `StepRng` directly, making it a bit // more clear it is intended for testing. -#[cfg(all(feature = "small_rng", target_pointer_width = "64"))] -mod xoshiro256plusplus; +#[cfg(feature = "small_rng")] mod small; #[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))] 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(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 = "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(feature = "getrandom")] pub use rand_core::OsRng; +#[cfg(feature = "getrandom")] +pub use rand_core::OsRng; diff --git a/src/rngs/reseeding.rs b/src/rngs/reseeding.rs index 752952e67e..a0076f959a 100644 --- a/src/rngs/reseeding.rs +++ b/src/rngs/reseeding.rs @@ -12,8 +12,8 @@ use core::mem::size_of_val; -use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; 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 /// ability to reseed it. @@ -59,7 +59,7 @@ use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng}; /// use rand::rngs::OsRng; /// use rand::rngs::ReseedingRng; /// -/// let prng = ChaCha20Core::from_entropy(); +/// let prng = ChaCha20Core::from_os_rng(); /// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng); /// /// println!("{}", reseeding_rng.random::()); @@ -75,12 +75,12 @@ use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng}; pub struct ReseedingRng(BlockRng>) where R: BlockRngCore + SeedableRng, - Rsdr: RngCore; + Rsdr: TryRngCore; impl ReseedingRng where R: BlockRngCore + SeedableRng, - Rsdr: RngCore, + Rsdr: TryRngCore, { /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG /// to use as reseeder. @@ -95,7 +95,7 @@ where /// Immediately reseed the generator /// /// 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.core.reseed() } @@ -103,9 +103,10 @@ where // TODO: this should be implemented for any type where the inner type // implements RngCore, but we can't specify that because ReseedingCore is private -impl RngCore for ReseedingRng +impl RngCore for ReseedingRng where R: BlockRngCore + SeedableRng, + Rsdr: TryRngCore, { #[inline(always)] fn next_u32(&mut self) -> u32 { @@ -120,16 +121,12 @@ where fn fill_bytes(&mut self, dest: &mut [u8]) { self.0.fill_bytes(dest) } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.0.try_fill_bytes(dest) - } } impl Clone for ReseedingRng where R: BlockRngCore + SeedableRng + Clone, - Rsdr: RngCore + Clone, + Rsdr: TryRngCore + Clone, { fn clone(&self) -> ReseedingRng { // Recreating `BlockRng` seems easier than cloning it and resetting @@ -141,7 +138,7 @@ where impl CryptoRng for ReseedingRng where R: BlockRngCore + SeedableRng + CryptoBlockRng, - Rsdr: CryptoRng, + Rsdr: TryCryptoRng, { } @@ -156,7 +153,7 @@ struct ReseedingCore { impl BlockRngCore for ReseedingCore where R: BlockRngCore + SeedableRng, - Rsdr: RngCore, + Rsdr: TryRngCore, { type Item = ::Item; type Results = ::Results; @@ -177,7 +174,7 @@ where impl ReseedingCore where R: BlockRngCore + SeedableRng, - Rsdr: RngCore, + Rsdr: TryRngCore, { /// Create a new `ReseedingCore`. fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { @@ -202,8 +199,8 @@ where } /// Reseed the internal PRNG. - fn reseed(&mut self) -> Result<(), Error> { - R::from_rng(&mut self.reseeder).map(|result| { + fn reseed(&mut self) -> Result<(), Rsdr::Error> { + R::try_from_rng(&mut self.reseeder).map(|result| { self.bytes_until_reseed = self.threshold; self.inner = result }) @@ -228,7 +225,7 @@ where impl Clone for ReseedingCore where R: BlockRngCore + SeedableRng + Clone, - Rsdr: RngCore + Clone, + Rsdr: TryRngCore + Clone, { fn clone(&self) -> ReseedingCore { ReseedingCore { @@ -243,22 +240,23 @@ where impl CryptoBlockRng for ReseedingCore where R: BlockRngCore + SeedableRng + CryptoBlockRng, - Rsdr: CryptoRng, -{} + Rsdr: TryCryptoRng, +{ +} #[cfg(feature = "std_rng")] #[cfg(test)] mod test { - use crate::{Rng, SeedableRng}; use crate::rngs::mock::StepRng; use crate::rngs::std::Core; + use crate::{Rng, SeedableRng}; use super::ReseedingRng; #[test] fn test_reseeding() { 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 mut reseeding = ReseedingRng::new(rng, thresh, zero); @@ -276,11 +274,10 @@ mod test { } #[test] + #[allow(clippy::redundant_clone)] fn test_clone_reseeding() { - #![allow(clippy::redundant_clone)] - 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 first: u32 = rng1.random(); diff --git a/src/rngs/small.rs b/src/rngs/small.rs index 2841b0b5dd..12276885f6 100644 --- a/src/rngs/small.rs +++ b/src/rngs/small.rs @@ -8,7 +8,7 @@ //! A small fast RNG -use rand_core::{Error, RngCore, SeedableRng}; +use rand_core::{RngCore, SeedableRng}; #[cfg(target_pointer_width = "64")] type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus; @@ -55,15 +55,12 @@ impl RngCore for SmallRng { #[inline(always)] fn fill_bytes(&mut self, dest: &mut [u8]) { - self.0.fill_bytes(dest); - } - - #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.0.try_fill_bytes(dest) + self.0.fill_bytes(dest) } } +rand_core::impl_try_rng_from_rng_core!(SmallRng); + impl SmallRng { /// Construct an instance seeded from another `Rng` /// @@ -76,8 +73,8 @@ impl SmallRng { /// let rng = SmallRng::from_rng(rand::thread_rng()); /// ``` #[inline(always)] - pub fn from_rng(rng: R) -> Result { - Rng::from_rng(rng).map(SmallRng) + pub fn from_rng(rng: R) -> Self { + Self(Rng::from_rng(rng)) } /// Construct an instance seeded from the thread-local RNG diff --git a/src/rngs/std.rs b/src/rngs/std.rs index 3de125f3e5..34a6fa8cdf 100644 --- a/src/rngs/std.rs +++ b/src/rngs/std.rs @@ -8,7 +8,7 @@ //! The standard RNG -use crate::{CryptoRng, Error, RngCore, SeedableRng}; +use rand_core::{CryptoRng, RngCore, SeedableRng}; #[cfg(any(test, feature = "getrandom"))] pub(crate) use rand_chacha::ChaCha12Core as Core; @@ -20,7 +20,7 @@ use rand_chacha::ChaCha12Rng as Rng; /// (meaning a cryptographically secure PRNG). /// /// 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. /// /// The algorithm is deterministic but should not be considered reproducible @@ -46,13 +46,8 @@ impl RngCore for StdRng { } #[inline(always)] - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.0.fill_bytes(dest); - } - - #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.0.try_fill_bytes(dest) + fn fill_bytes(&mut self, dst: &mut [u8]) { + self.0.fill_bytes(dst) } } @@ -64,15 +59,11 @@ impl SeedableRng for StdRng { fn from_seed(seed: Self::Seed) -> Self { StdRng(Rng::from_seed(seed)) } - - #[inline(always)] - fn from_rng(rng: R) -> Result { - Rng::from_rng(rng).map(StdRng) - } } impl CryptoRng for StdRng {} +rand_core::impl_try_crypto_rng_from_crypto_rng!(StdRng); #[cfg(test)] mod test { @@ -92,7 +83,7 @@ mod test { let mut rng0 = StdRng::from_seed(seed); 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(); assert_eq!([x0, x1], target); diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index f79ded83e3..0865414967 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -9,14 +9,15 @@ //! Thread-local random number generator use core::cell::UnsafeCell; +use std::fmt; use std::rc::Rc; use std::thread_local; -use std::fmt; + +use rand_core::{CryptoRng, RngCore, SeedableRng}; use super::std::Core; -use crate::rngs::ReseedingRng; use crate::rngs::OsRng; -use crate::{CryptoRng, Error, RngCore, SeedableRng}; +use crate::rngs::ReseedingRng; // Rationale for using `UnsafeCell` in `ThreadRng`: // @@ -76,7 +77,10 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64; /// /// [`ReseedingRng`]: crate::rngs::ReseedingRng /// [`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)] pub struct ThreadRng { // Rc is explicitly !Send and !Sync @@ -87,7 +91,7 @@ impl ThreadRng { /// Immediately reseed the generator /// /// 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 // creates another mutable reference 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 // within thread-local destructors. See #968. static THREAD_RNG_KEY: Rc>> = { - 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)); let rng = ReseedingRng::new(r, THREAD_RNG_RESEED_THRESHOLD, @@ -132,7 +136,10 @@ thread_local!( /// 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 { let rng = THREAD_RNG_KEY.with(|t| t.clone()); ThreadRng { rng } @@ -161,23 +168,18 @@ impl RngCore for ThreadRng { rng.next_u64() } + #[inline(always)] fn fill_bytes(&mut self, dest: &mut [u8]) { // SAFETY: We must make sure to stop using `rng` before anyone else // creates another mutable reference let rng = unsafe { &mut *self.rng.get() }; 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 {} +rand_core::impl_try_crypto_rng_from_crypto_rng!(ThreadRng); #[cfg(test)] mod test { @@ -193,6 +195,9 @@ mod test { fn test_debug_output() { // We don't care about the exact output here, but it must not include // 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 { .. }" + ); } } diff --git a/src/rngs/xoshiro128plusplus.rs b/src/rngs/xoshiro128plusplus.rs index ece98fafd6..416ea91a9f 100644 --- a/src/rngs/xoshiro128plusplus.rs +++ b/src/rngs/xoshiro128plusplus.rs @@ -6,10 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; -use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next}; +use rand_core::impls::{fill_bytes_via_next, next_u64_via_u32}; 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. /// @@ -20,7 +20,7 @@ use rand_core::{SeedableRng, RngCore, Error}; /// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by /// David Blackman and Sebastiano Vigna. #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct Xoshiro128PlusPlus { s: [u32; 4], } @@ -61,7 +61,7 @@ impl SeedableRng for Xoshiro128PlusPlus { impl RngCore for Xoshiro128PlusPlus { #[inline] fn next_u32(&mut self) -> u32 { - let result_starstar = self.s[0] + let res = self.s[0] .wrapping_add(self.s[3]) .rotate_left(7) .wrapping_add(self.s[0]); @@ -77,7 +77,7 @@ impl RngCore for Xoshiro128PlusPlus { self.s[3] = self.s[3].rotate_left(11); - result_starstar + res } #[inline] @@ -86,30 +86,27 @@ impl RngCore for Xoshiro128PlusPlus { } #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - fill_bytes_via_next(self, dest); - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) + fn fill_bytes(&mut self, dst: &mut [u8]) { + fill_bytes_via_next(self, dst) } } +rand_core::impl_try_rng_from_rng_core!(Xoshiro128PlusPlus); + #[cfg(test)] mod tests { - use super::*; + use super::Xoshiro128PlusPlus; + use rand_core::{RngCore, SeedableRng}; #[test] fn reference() { - let mut rng = Xoshiro128PlusPlus::from_seed( - [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]); + let mut rng = + 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: // http://xoshiro.di.unimi.it/xoshiro128plusplus.c let expected = [ - 641, 1573767, 3222811527, 3517856514, 836907274, 4247214768, - 3867114732, 1355841295, 495546011, 621204420, + 641, 1573767, 3222811527, 3517856514, 836907274, 4247214768, 3867114732, 1355841295, + 495546011, 621204420, ]; for &e in &expected { assert_eq!(rng.next_u32(), e); diff --git a/src/rngs/xoshiro256plusplus.rs b/src/rngs/xoshiro256plusplus.rs index 8ffb18b803..0fdc66df7c 100644 --- a/src/rngs/xoshiro256plusplus.rs +++ b/src/rngs/xoshiro256plusplus.rs @@ -6,10 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; use rand_core::impls::fill_bytes_via_next; 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. /// @@ -20,7 +20,7 @@ use rand_core::{SeedableRng, RngCore, Error}; /// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by /// David Blackman and Sebastiano Vigna. #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct Xoshiro256PlusPlus { s: [u64; 4], } @@ -63,12 +63,13 @@ impl RngCore for Xoshiro256PlusPlus { fn next_u32(&mut self) -> u32 { // The lowest bits have some linear dependencies, so we use the // upper bits instead. - (self.next_u64() >> 32) as u32 + let val = self.next_u64(); + (val >> 32) as u32 } #[inline] fn next_u64(&mut self) -> u64 { - let result_plusplus = self.s[0] + let res = self.s[0] .wrapping_add(self.s[3]) .rotate_left(23) .wrapping_add(self.s[0]); @@ -84,36 +85,41 @@ impl RngCore for Xoshiro256PlusPlus { self.s[3] = self.s[3].rotate_left(45); - result_plusplus + res } #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - fill_bytes_via_next(self, dest); - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) + fn fill_bytes(&mut self, dst: &mut [u8]) { + fill_bytes_via_next(self, dst) } } +rand_core::impl_try_rng_from_rng_core!(Xoshiro256PlusPlus); + #[cfg(test)] mod tests { - use super::*; + use super::Xoshiro256PlusPlus; + use rand_core::{RngCore, SeedableRng}; #[test] fn reference() { - let mut rng = Xoshiro256PlusPlus::from_seed( - [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, 0, 0, 0]); + let mut rng = Xoshiro256PlusPlus::from_seed([ + 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, + 0, 0, 0, + ]); // These values were produced with the reference implementation: // http://xoshiro.di.unimi.it/xoshiro256plusplus.c let expected = [ - 41943041, 58720359, 3588806011781223, 3591011842654386, - 9228616714210784205, 9973669472204895162, 14011001112246962877, - 12406186145184390807, 15849039046786891736, 10450023813501588000, + 41943041, + 58720359, + 3588806011781223, + 3591011842654386, + 9228616714210784205, + 9973669472204895162, + 14011001112246962877, + 12406186145184390807, + 15849039046786891736, + 10450023813501588000, ]; for &e in &expected { assert_eq!(rng.next_u64(), e);