Add TryRngCore and TryCryptoRng traits (#1424)

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

View File

@ -92,7 +92,7 @@ compiler versions will be compatible. This is especially true of Rand's
experimental `simd_support` feature.
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.

View File

@ -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(|| {

View File

@ -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 {

View File

@ -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[..]);

View File

@ -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)
})

View File

@ -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);
}
{

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

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

View File

@ -54,10 +54,9 @@
//! [`fill_bytes`]: RngCore::fill_bytes
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),
}
}
}

View File

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

View File

@ -74,7 +74,7 @@ impl Observable for u64 {
/// unaltered.
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::*;

View File

@ -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::*;

View File

@ -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);
}

View File

@ -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();

View File

@ -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();
//! ```

View File

@ -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)]

View File

@ -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)]

View File

@ -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(())
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);
/// ```
///

View File

@ -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> {

View File

@ -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;

View File

@ -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};

View File

@ -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]);
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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 { .. }"
);
}
}

View File

@ -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);

View File

@ -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);