Add TryRngCore
and TryCryptoRng
traits (#1424)
This reworks fallibility, replacing the fixed `Error` type.
This commit is contained in:
parent
1f818787ca
commit
fba5521f0f
@ -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.
|
||||
|
@ -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(|| {
|
||||
|
@ -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 {
|
||||
|
@ -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<u16> = 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<u16> = 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<u64> = 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<u64> = 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[..]);
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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<CyclesPerByte>) {
|
||||
distr_float!(g, "log_normal", f64, LogNormal::new(-1.23, 4.56).unwrap());
|
||||
g.throughput(Throughput::Bytes(size_of::<f64>() as u64 * RAND_BENCH_N));
|
||||
g.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<CyclesPerByte>) {
|
||||
|
||||
{
|
||||
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<CyclesPerByte>) {
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<T> fmt::Debug for Array64<T> {
|
||||
}
|
||||
|
||||
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<u32>;
|
||||
|
||||
#[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: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de> {
|
||||
$abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
91
rand_core/src/blanket_impls.rs
Normal file
91
rand_core/src/blanket_impls.rs
Normal file
@ -0,0 +1,91 @@
|
||||
#[cfg(feature = "alloc")] use alloc::boxed::Box;
|
||||
|
||||
use crate::{CryptoRng, RngCore, TryCryptoRng, TryRngCore};
|
||||
|
||||
impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
|
||||
#[inline(always)]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
R::next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
R::next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
R::fill_bytes(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
|
||||
|
||||
impl<'a, R: TryRngCore + ?Sized> TryRngCore for &'a mut R {
|
||||
type Error = R::Error;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
R::try_next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
R::try_next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
R::try_fill_bytes(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: TryCryptoRng + ?Sized> TryCryptoRng for &'a mut R {}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
impl<R: RngCore + ?Sized> RngCore for Box<R> {
|
||||
#[inline(always)]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
R::next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
R::next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
R::fill_bytes(self, dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
impl<R: TryRngCore + ?Sized> TryRngCore for Box<R> {
|
||||
type Error = R::Error;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
R::try_next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
R::try_next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
R::try_fill_bytes(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
impl<R: TryCryptoRng + ?Sized> TryCryptoRng for Box<R> {}
|
@ -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
|
||||
@ -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<R: BlockRngCore<Item = u32>> RngCore for BlockRng<R> {
|
||||
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<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
|
||||
@ -256,8 +249,13 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
|
||||
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<S: TryRngCore>(rng: S) -> Result<Self, S::Error> {
|
||||
R::try_from_rng(rng).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,14 +275,12 @@ impl<R: CryptoBlockRng + BlockRngCore<Item = u32>> CryptoRng for BlockRng<R> {}
|
||||
/// then the other half is then consumed, however both [`next_u64`] and
|
||||
/// [`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<R: BlockRngCore + ?Sized> {
|
||||
@ -402,12 +398,6 @@ impl<R: BlockRngCore<Item = u64>> RngCore for BlockRng64<R> {
|
||||
read_len += filled_u8;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
self.fill_bytes(dest);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
|
||||
@ -424,8 +414,13 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
|
||||
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<S: TryRngCore>(rng: S) -> Result<Self, S::Error> {
|
||||
R::try_from_rng(rng).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,8 +428,8 @@ impl<R: CryptoBlockRng + BlockRngCore<Item = u64>> CryptoRng for BlockRng64<R> {
|
||||
|
||||
#[cfg(test)]
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,226 +0,0 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Error types
|
||||
|
||||
use core::fmt;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
#[cfg(feature = "std")] use std::boxed::Box;
|
||||
|
||||
/// Error type of random number generators
|
||||
///
|
||||
/// In order to be compatible with `std` and `no_std`, this type has two
|
||||
/// possible implementations: with `std` a boxed `Error` trait object is stored,
|
||||
/// while with `no_std` we merely store an error code.
|
||||
pub struct Error {
|
||||
#[cfg(feature = "std")]
|
||||
inner: Box<dyn std::error::Error + Send + Sync + 'static>,
|
||||
#[cfg(not(feature = "std"))]
|
||||
code: NonZeroU32,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Codes at or above this point can be used by users to define their own
|
||||
/// custom errors.
|
||||
///
|
||||
/// This has a fixed value of `(1 << 31) + (1 << 30) = 0xC000_0000`,
|
||||
/// therefore the number of values available for custom codes is `1 << 30`.
|
||||
///
|
||||
/// This is identical to [`getrandom::Error::CUSTOM_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.CUSTOM_START).
|
||||
pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
|
||||
/// Codes below this point represent OS Errors (i.e. positive i32 values).
|
||||
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
|
||||
/// reserved for use by the `rand` and `getrandom` crates.
|
||||
///
|
||||
/// This is identical to [`getrandom::Error::INTERNAL_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.INTERNAL_START).
|
||||
pub const INTERNAL_START: u32 = 1 << 31;
|
||||
|
||||
/// Construct from any type supporting `std::error::Error`
|
||||
///
|
||||
/// Available only when configured with `std`.
|
||||
///
|
||||
/// See also `From<NonZeroU32>`, which is available with and without `std`.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||
#[inline]
|
||||
pub fn new<E>(err: E) -> Self
|
||||
where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
Error { inner: err.into() }
|
||||
}
|
||||
|
||||
/// Reference the inner error (`std` only)
|
||||
///
|
||||
/// When configured with `std`, this is a trivial operation and never
|
||||
/// panics. Without `std`, this method is simply unavailable.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||
#[inline]
|
||||
pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
|
||||
&*self.inner
|
||||
}
|
||||
|
||||
/// Unwrap the inner error (`std` only)
|
||||
///
|
||||
/// When configured with `std`, this is a trivial operation and never
|
||||
/// panics. Without `std`, this method is simply unavailable.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||
#[inline]
|
||||
pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Extract the raw OS error code (if this error came from the OS)
|
||||
///
|
||||
/// This method is identical to `std::io::Error::raw_os_error()`, except
|
||||
/// that it works in `no_std` contexts. If this method returns `None`, the
|
||||
/// error value can still be formatted via the `Display` implementation.
|
||||
#[inline]
|
||||
pub fn raw_os_error(&self) -> Option<i32> {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
if let Some(e) = self.inner.downcast_ref::<std::io::Error>() {
|
||||
return e.raw_os_error();
|
||||
}
|
||||
}
|
||||
match self.code() {
|
||||
Some(code) if u32::from(code) < Self::INTERNAL_START => Some(u32::from(code) as i32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the error code, if any.
|
||||
///
|
||||
/// If this `Error` was constructed via `From<NonZeroU32>`, then this method
|
||||
/// will return this `NonZeroU32` code (for `no_std` this is always the
|
||||
/// case). Otherwise, this method will return `None`.
|
||||
#[inline]
|
||||
pub fn code(&self) -> Option<NonZeroU32> {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
self.inner.downcast_ref::<ErrorCode>().map(|c| c.0)
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
Some(self.code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
write!(f, "Error {{ inner: {:?} }}", self.inner)
|
||||
}
|
||||
#[cfg(all(feature = "getrandom", not(feature = "std")))]
|
||||
{
|
||||
getrandom::Error::from(self.code).fmt(f)
|
||||
}
|
||||
#[cfg(not(any(feature = "getrandom", feature = "std")))]
|
||||
{
|
||||
write!(f, "Error {{ code: {} }}", self.code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
write!(f, "{}", self.inner)
|
||||
}
|
||||
#[cfg(all(feature = "getrandom", not(feature = "std")))]
|
||||
{
|
||||
getrandom::Error::from(self.code).fmt(f)
|
||||
}
|
||||
#[cfg(not(any(feature = "getrandom", feature = "std")))]
|
||||
{
|
||||
write!(f, "error code {}", self.code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NonZeroU32> for Error {
|
||||
#[inline]
|
||||
fn from(code: NonZeroU32) -> Self {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
Error {
|
||||
inner: Box::new(ErrorCode(code)),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
Error { code }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "getrandom")]
|
||||
impl From<getrandom::Error> for Error {
|
||||
#[inline]
|
||||
fn from(error: getrandom::Error) -> Self {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
Error {
|
||||
inner: Box::new(error),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
Error { code: error.code() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {
|
||||
#[inline]
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
self.inner.source()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<Error> for std::io::Error {
|
||||
#[inline]
|
||||
fn from(error: Error) -> Self {
|
||||
if let Some(code) = error.raw_os_error() {
|
||||
std::io::Error::from_raw_os_error(code)
|
||||
} else {
|
||||
std::io::Error::new(std::io::ErrorKind::Other, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct ErrorCode(NonZeroU32);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl fmt::Display for ErrorCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "error code {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ErrorCode {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(feature = "getrandom")]
|
||||
#[test]
|
||||
fn test_error_codes() {
|
||||
// Make sure the values are the same as in `getrandom`.
|
||||
assert_eq!(super::Error::CUSTOM_START, getrandom::Error::CUSTOM_START);
|
||||
assert_eq!(super::Error::INTERNAL_START, getrandom::Error::INTERNAL_START);
|
||||
}
|
||||
}
|
@ -74,7 +74,7 @@ impl Observable for u64 {
|
||||
/// unaltered.
|
||||
fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usize) {
|
||||
let size = core::mem::size_of::<T>();
|
||||
let byte_len = min(src.len() * size, dest.len());
|
||||
let byte_len = min(core::mem::size_of_val(src), dest.len());
|
||||
let num_chunks = (byte_len + size - 1) / size;
|
||||
|
||||
// Byte-swap for portability of results. This must happen before copying
|
||||
@ -160,6 +160,56 @@ pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
|
||||
u64::from_le_bytes(buf)
|
||||
}
|
||||
|
||||
/// Implement [`TryRngCore`] for a type implementing [`RngCore`].
|
||||
///
|
||||
/// Ideally, `rand_core` would define blanket impls for this, but they conflict with blanket impls
|
||||
/// for `&mut R` and `Box<R>`, so until specialziation is stabilized, implementer crates
|
||||
/// have to implement `TryRngCore` directly.
|
||||
#[macro_export]
|
||||
macro_rules! impl_try_rng_from_rng_core {
|
||||
($t:ty) => {
|
||||
impl $crate::TryRngCore for $t {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
#[inline]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
Ok($crate::RngCore::next_u32(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
Ok($crate::RngCore::next_u64(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
$crate::RngCore::fill_bytes(self, dst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement [`TryCryptoRng`] and [`TryRngCore`] for a type implementing [`CryptoRng`].
|
||||
///
|
||||
/// Ideally, `rand_core` would define blanket impls for this, but they conflict with blanket impls
|
||||
/// for `&mut R` and `Box<R>`, so until specialziation is stabilized, implementer crates
|
||||
/// have to implement `TryRngCore` and `TryCryptoRng` directly.
|
||||
#[macro_export]
|
||||
macro_rules! impl_try_crypto_rng_from_crypto_rng {
|
||||
($t:ty) => {
|
||||
$crate::impl_try_rng_from_rng_core!($t);
|
||||
|
||||
impl $crate::TryCryptoRng for $t {}
|
||||
|
||||
/// Check at compile time that `$t` implements `CryptoRng`
|
||||
const _: () = {
|
||||
const fn check_crypto_rng_impl<T: $crate::CryptoRng>() {}
|
||||
check_crypto_rng_impl::<$t>();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -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 fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
/// impls::fill_bytes_via_next(self, dst)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
/// Ok(self.fill_bytes(dest))
|
||||
/// }
|
||||
/// }
|
||||
/// rand_core::impl_try_rng_from_rng_core!(CountingRng);
|
||||
/// ```
|
||||
///
|
||||
/// [`rand`]: https://docs.rs/rand
|
||||
/// [`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<u32, Self::Error>;
|
||||
/// Return the next random `u64`.
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error>;
|
||||
/// Fill `dest` entirely with random data.
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error>;
|
||||
|
||||
/// Wrap RNG with the [`UnwrapErr`] wrapper.
|
||||
fn unwrap_err(self) -> UnwrapErr<Self>
|
||||
where Self: Sized {
|
||||
UnwrapErr(self)
|
||||
}
|
||||
|
||||
/// Convert an [`RngCore`] to a [`RngReadAdapter`].
|
||||
#[cfg(feature = "std")]
|
||||
fn read_adapter(&mut self) -> RngReadAdapter<'_, Self>
|
||||
where Self: Sized {
|
||||
RngReadAdapter { inner: self }
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker trait used to indicate that a [`TryRngCore`] implementation is
|
||||
/// supposed to be cryptographically secure.
|
||||
///
|
||||
/// See [`CryptoRng`] docs for more information about cryptographically secure generators.
|
||||
pub trait TryCryptoRng: TryRngCore {}
|
||||
|
||||
/// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`]
|
||||
/// by panicking on potential errors.
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct UnwrapErr<R: TryRngCore>(pub R);
|
||||
|
||||
impl<R: TryRngCore> RngCore for UnwrapErr<R> {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.0.try_next_u32().unwrap()
|
||||
}
|
||||
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.0.try_next_u64().unwrap()
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
self.0.try_fill_bytes(dst).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TryCryptoRng> CryptoRng for UnwrapErr<R> {}
|
||||
|
||||
/// A random number generator that can be explicitly seeded.
|
||||
///
|
||||
/// 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<R: RngCore>(mut rng: R) -> Result<Self, Error> {
|
||||
fn from_rng(mut rng: impl RngCore) -> Self {
|
||||
let mut seed = Self::Seed::default();
|
||||
rng.fill_bytes(seed.as_mut());
|
||||
Self::from_seed(seed)
|
||||
}
|
||||
|
||||
/// Create a new PRNG seeded from a potentially fallible `Rng`.
|
||||
///
|
||||
/// See [`from_rng`][SeedableRng::from_rng] docs for more infromation.
|
||||
fn try_from_rng<R: TryRngCore>(mut rng: R) -> Result<Self, R::Error> {
|
||||
let mut seed = Self::Seed::default();
|
||||
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 {
|
||||
fn from_os_rng() -> Self {
|
||||
match Self::try_from_os_rng() {
|
||||
Ok(res) => res,
|
||||
Err(err) => panic!("from_os_rng failed: {}", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Self, getrandom::Error> {
|
||||
let mut seed = Self::Seed::default();
|
||||
if let Err(err) = getrandom::getrandom(seed.as_mut()) {
|
||||
panic!("from_entropy 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<R: RngCore + ?Sized> RngCore for Box<R> {
|
||||
#[inline(always)]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
(**self).next_u32()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
(**self).next_u64()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
(**self).fill_bytes(dest)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
(**self).try_fill_bytes(dest)
|
||||
getrandom::getrandom(seed.as_mut())?;
|
||||
let res = Self::from_seed(seed);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,38 +471,32 @@ impl<R: RngCore + ?Sized> RngCore for Box<R> {
|
||||
/// ```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<R: RngCore + ?Sized> std::io::Read for RngReadAdapter<'_, R> {
|
||||
impl<R: TryRngCore + ?Sized> std::io::Read for RngReadAdapter<'_, R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
|
||||
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<R: RngCore + ?Sized> std::fmt::Debug for RngReadAdapter<'_, R> {
|
||||
impl<R: TryRngCore + ?Sized> std::fmt::Debug for RngReadAdapter<'_, R> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ReadAdapter").finish()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `CryptoRng` for references to a `CryptoRng`.
|
||||
impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
|
||||
|
||||
// Implement `CryptoRng` for boxed references to a `CryptoRng`.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -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<u32, Self::Error> {
|
||||
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<u64, Self::Error> {
|
||||
let mut buf = [0u8; 8];
|
||||
getrandom(&mut buf)?;
|
||||
Ok(u64::from_ne_bytes(buf))
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
//! ```
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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<R: Rng>(
|
||||
rng: &mut R,
|
||||
) -> impl Iterator<Item = i32> + '_ {
|
||||
fn ten_dice_rolls_other_than_five<R: Rng>(rng: &mut R) -> impl Iterator<Item = i32> + '_ {
|
||||
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);
|
||||
|
@ -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);
|
||||
/// ```
|
||||
///
|
||||
|
@ -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>() -> T
|
||||
where Standard: Distribution<T> {
|
||||
|
@ -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;
|
||||
|
84
src/rng.rs
84
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<T: Fill + ?Sized>(&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<T: Fill + ?Sized>(&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,7 +304,10 @@ 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<T>(&mut self) -> T
|
||||
where Standard: Distribution<T> {
|
||||
self.random()
|
||||
@ -353,18 +325,17 @@ impl<R: RngCore + ?Sized> 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<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error>;
|
||||
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R);
|
||||
}
|
||||
|
||||
macro_rules! impl_fill_each {
|
||||
() => {};
|
||||
($t:ty) => {
|
||||
impl Fill for [$t] {
|
||||
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
|
||||
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
|
||||
for elt in self.iter_mut() {
|
||||
*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<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
|
||||
rng.try_fill_bytes(self)
|
||||
fn fill<R: Rng + ?Sized>(&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<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
|
||||
fn fill<R: Rng + ?Sized>(&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<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
|
||||
fn fill<R: Rng + ?Sized>(&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<T, const N: usize> Fill for [T; N]
|
||||
where [T]: Fill
|
||||
{
|
||||
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
|
||||
self[..].try_fill(rng)
|
||||
fn fill<R: Rng + ?Sized>(&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};
|
||||
|
@ -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);
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
impls::fill_bytes_via_next(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
self.fill_bytes(dest);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
rand_core::impl_try_rng_from_rng_core!(StepRng);
|
||||
|
||||
#[cfg(test)]
|
||||
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<bool> =
|
||||
rng.sample_iter(Standard).take(6).collect();
|
||||
let result: alloc::vec::Vec<bool> = rng.sample_iter(Standard).take(6).collect();
|
||||
assert_eq!(&result, &[false, true, false, true, false, true]);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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::<u64>());
|
||||
@ -75,12 +75,12 @@ use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
|
||||
pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
|
||||
where
|
||||
R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore;
|
||||
Rsdr: TryRngCore;
|
||||
|
||||
impl<R, Rsdr> ReseedingRng<R, Rsdr>
|
||||
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<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr>
|
||||
impl<R, Rsdr> RngCore for ReseedingRng<R, Rsdr>
|
||||
where
|
||||
R: BlockRngCore<Item = u32> + 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<R, Rsdr> Clone for ReseedingRng<R, Rsdr>
|
||||
where
|
||||
R: BlockRngCore + SeedableRng + Clone,
|
||||
Rsdr: RngCore + Clone,
|
||||
Rsdr: TryRngCore + Clone,
|
||||
{
|
||||
fn clone(&self) -> ReseedingRng<R, Rsdr> {
|
||||
// Recreating `BlockRng` seems easier than cloning it and resetting
|
||||
@ -141,7 +138,7 @@ where
|
||||
impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
|
||||
where
|
||||
R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng,
|
||||
Rsdr: CryptoRng,
|
||||
Rsdr: TryCryptoRng,
|
||||
{
|
||||
}
|
||||
|
||||
@ -156,7 +153,7 @@ struct ReseedingCore<R, Rsdr> {
|
||||
impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr>
|
||||
where
|
||||
R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore,
|
||||
Rsdr: TryRngCore,
|
||||
{
|
||||
type Item = <R as BlockRngCore>::Item;
|
||||
type Results = <R as BlockRngCore>::Results;
|
||||
@ -177,7 +174,7 @@ where
|
||||
impl<R, Rsdr> ReseedingCore<R, Rsdr>
|
||||
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<R, Rsdr> Clone for ReseedingCore<R, Rsdr>
|
||||
where
|
||||
R: BlockRngCore + SeedableRng + Clone,
|
||||
Rsdr: RngCore + Clone,
|
||||
Rsdr: TryRngCore + Clone,
|
||||
{
|
||||
fn clone(&self) -> ReseedingCore<R, Rsdr> {
|
||||
ReseedingCore {
|
||||
@ -243,22 +240,23 @@ where
|
||||
impl<R, Rsdr> CryptoBlockRng for ReseedingCore<R, Rsdr>
|
||||
where
|
||||
R: BlockRngCore<Item = u32> + 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();
|
||||
|
@ -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,14 +55,11 @@ impl RngCore for SmallRng {
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
self.0.fill_bytes(dest);
|
||||
self.0.fill_bytes(dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
self.0.try_fill_bytes(dest)
|
||||
}
|
||||
}
|
||||
rand_core::impl_try_rng_from_rng_core!(SmallRng);
|
||||
|
||||
impl SmallRng {
|
||||
/// 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<R: RngCore>(rng: R) -> Result<Self, Error> {
|
||||
Rng::from_rng(rng).map(SmallRng)
|
||||
pub fn from_rng<R: RngCore>(rng: R) -> Self {
|
||||
Self(Rng::from_rng(rng))
|
||||
}
|
||||
|
||||
/// Construct an instance seeded from the thread-local RNG
|
||||
|
@ -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;
|
||||
@ -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<R: RngCore>(rng: R) -> Result<Self, Error> {
|
||||
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);
|
||||
|
@ -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<UnsafeCell<ReseedingRng<Core, OsRng>>> = {
|
||||
let r = Core::from_rng(OsRng).unwrap_or_else(|err|
|
||||
let r = Core::try_from_os_rng().unwrap_or_else(|err|
|
||||
panic!("could not initialize thread_rng: {}", err));
|
||||
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 { .. }"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
///
|
||||
@ -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);
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
fill_bytes_via_next(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
self.fill_bytes(dest);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
rand_core::impl_try_rng_from_rng_core!(Xoshiro128PlusPlus);
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
|
@ -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.
|
||||
///
|
||||
@ -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);
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
fill_bytes_via_next(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
self.fill_bytes(dest);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
rand_core::impl_try_rng_from_rng_core!(Xoshiro256PlusPlus);
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user