diff --git a/benches/generators.rs b/benches/generators.rs index 96fa302b6a..12b8460f0b 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -50,7 +50,7 @@ gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy()); gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy()); gen_bytes!(gen_bytes_std, StdRng::from_entropy()); #[cfg(feature = "small_rng")] -gen_bytes!(gen_bytes_small, SmallRng::from_entropy()); +gen_bytes!(gen_bytes_small, SmallRng::from_thread_rng()); gen_bytes!(gen_bytes_os, OsRng); macro_rules! gen_uint { @@ -80,7 +80,7 @@ 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()); #[cfg(feature = "small_rng")] -gen_uint!(gen_u32_small, u32, SmallRng::from_entropy()); +gen_uint!(gen_u32_small, u32, SmallRng::from_thread_rng()); gen_uint!(gen_u32_os, u32, OsRng); gen_uint!(gen_u64_step, u64, StepRng::new(0, 1)); @@ -93,7 +93,7 @@ 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()); #[cfg(feature = "small_rng")] -gen_uint!(gen_u64_small, u64, SmallRng::from_entropy()); +gen_uint!(gen_u64_small, u64, SmallRng::from_thread_rng()); gen_uint!(gen_u64_os, u64, OsRng); macro_rules! init_gen { diff --git a/benches/uniform.rs b/benches/uniform.rs index d0128d5a48..0ed0f2cde4 100644 --- a/benches/uniform.rs +++ b/benches/uniform.rs @@ -23,7 +23,7 @@ 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_entropy(); + let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let x = rng.gen::<$U>(); let bits = (<$T>::BITS / 2); let mask = (1 as $U).wrapping_neg() >> bits; @@ -35,7 +35,7 @@ macro_rules! sample { }); $g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| { - let mut rng = <$R>::from_entropy(); + let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let x = rng.gen::<$U>(); let bits = (<$T>::BITS / 2); let mask = (1 as $U).wrapping_neg() >> bits; diff --git a/benches/uniform_float.rs b/benches/uniform_float.rs index 3366ad3f98..957ff1b8ec 100644 --- a/benches/uniform_float.rs +++ b/benches/uniform_float.rs @@ -27,7 +27,7 @@ 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_entropy(); + let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let (mut low, mut high); loop { low = <$T>::from_bits(rng.gen()); @@ -63,7 +63,7 @@ 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_entropy(); + let mut rng = <$R>::from_rng(thread_rng()).unwrap(); let dist = loop { let low = <$T>::from_bits(rng.gen()); let high = <$T>::from_bits(rng.gen()); diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs index 387e7aa395..a8cefc8e40 100644 --- a/rand_core/src/block.rs +++ b/rand_core/src/block.rs @@ -80,7 +80,7 @@ pub trait BlockRngCore { /// A marker trait used to indicate that an [`RngCore`] implementation is /// supposed to be cryptographically secure. /// -/// See [`CryptoRng`][crate::CryptoRng] docs for more information. +/// See [`CryptoRng`] docs for more information. pub trait CryptoBlockRng: BlockRngCore { } /// A wrapper type implementing [`RngCore`] for some type implementing diff --git a/src/rngs/small.rs b/src/rngs/small.rs index a326175784..2841b0b5dd 100644 --- a/src/rngs/small.rs +++ b/src/rngs/small.rs @@ -22,18 +22,12 @@ type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus; /// Note that depending on the application, [`StdRng`] may be faster on many /// modern platforms while providing higher-quality randomness. Furthermore, /// `SmallRng` is **not** a good choice when: -/// - Security against prediction is important. Use [`StdRng`] instead. -/// - Seeds with many zeros are provided. In such cases, it takes `SmallRng` -/// about 10 samples to produce 0 and 1 bits with equal probability. Either -/// provide seeds with an approximately equal number of 0 and 1 (for example -/// by using [`SeedableRng::from_entropy`] or [`SeedableRng::seed_from_u64`]), -/// or use [`StdRng`] instead. /// -/// The algorithm is deterministic but should not be considered reproducible -/// due to dependence on platform and possible replacement in future -/// library versions. For a reproducible generator, use a named PRNG from an -/// external crate, e.g. [rand_xoshiro] or [rand_chacha]. -/// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html). +/// - Portability is required. Its implementation is not fixed. Use a named +/// generator from an external crate instead, for example [rand_xoshiro] or +/// [rand_chacha]. Refer also to +/// [The Book](https://rust-random.github.io/book/guide-rngs.html). +/// - Security against prediction is important. Use [`StdRng`] instead. /// /// The PRNG algorithm in `SmallRng` is chosen to be efficient on the current /// platform, without consideration for cryptography or security. The size of @@ -41,39 +35,7 @@ type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus; /// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit /// platforms. Both are also implemented by the [rand_xoshiro] crate. /// -/// # Examples -/// -/// Initializing `SmallRng` with a random seed can be done using [`SeedableRng::from_entropy`]: -/// -/// ``` -/// use rand::{Rng, SeedableRng}; -/// use rand::rngs::SmallRng; -/// -/// // Create small, cheap to initialize and fast RNG with a random seed. -/// // The randomness is supplied by the operating system. -/// let mut small_rng = SmallRng::from_entropy(); -/// # let v: u32 = small_rng.gen(); -/// ``` -/// -/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more -/// efficient: -/// -/// ``` -/// use rand::{SeedableRng, thread_rng}; -/// use rand::rngs::SmallRng; -/// -/// // Create a big, expensive to initialize and slower, but unpredictable RNG. -/// // This is cached and done only once per thread. -/// let mut thread_rng = thread_rng(); -/// // Create small, cheap to initialize and fast RNGs with random seeds. -/// // One can generally assume this won't fail. -/// let rngs: Vec = (0..10) -/// .map(|_| SmallRng::from_rng(&mut thread_rng).unwrap()) -/// .collect(); -/// ``` -/// /// [`StdRng`]: crate::rngs::StdRng -/// [`thread_rng`]: crate::thread_rng /// [rand_chacha]: https://crates.io/crates/rand_chacha /// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro #[cfg_attr(doc_cfg, doc(cfg(feature = "small_rng")))] @@ -102,21 +64,53 @@ impl RngCore for SmallRng { } } -impl SeedableRng for SmallRng { - type Seed = ::Seed; - +impl SmallRng { + /// Construct an instance seeded from another `Rng` + /// + /// We recommend that the source (master) RNG uses a different algorithm + /// (i.e. is not `SmallRng`) to avoid correlations between the child PRNGs. + /// + /// # Example + /// ``` + /// # use rand::rngs::SmallRng; + /// let rng = SmallRng::from_rng(rand::thread_rng()); + /// ``` #[inline(always)] - fn from_seed(seed: Self::Seed) -> Self { - SmallRng(Rng::from_seed(seed)) + pub fn from_rng(rng: R) -> Result { + Rng::from_rng(rng).map(SmallRng) } + /// Construct an instance seeded from the thread-local RNG + /// + /// # Panics + /// + /// This method panics only if [`thread_rng`](crate::thread_rng) fails to + /// initialize. + #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))] #[inline(always)] - fn from_rng(rng: R) -> Result { - Rng::from_rng(rng).map(SmallRng) + pub fn from_thread_rng() -> Self { + let mut seed = ::Seed::default(); + crate::thread_rng().fill_bytes(seed.as_mut()); + SmallRng(Rng::from_seed(seed)) } + /// Construct an instance from a `u64` seed + /// + /// This provides a convenient method of seeding a `SmallRng` from a simple + /// number by use of another algorithm to mutate and expand the input. + /// This is suitable for use with low Hamming Weight numbers like 0 and 1. + /// + /// **Warning:** the implementation is deterministic but not portable: + /// output values may differ according to platform and may be changed by a + /// future version of the library. + /// + /// # Example + /// ``` + /// # use rand::rngs::SmallRng; + /// let rng = SmallRng::seed_from_u64(1); + /// ``` #[inline(always)] - fn seed_from_u64(state: u64) -> Self { + pub fn seed_from_u64(state: u64) -> Self { SmallRng(Rng::seed_from_u64(state)) } } diff --git a/src/rngs/std.rs b/src/rngs/std.rs index ddc3014dfe..31b20a2dc5 100644 --- a/src/rngs/std.rs +++ b/src/rngs/std.rs @@ -57,7 +57,8 @@ impl RngCore for StdRng { } impl SeedableRng for StdRng { - type Seed = ::Seed; + // Fix to 256 bits. Changing this is a breaking change! + type Seed = [u8; 32]; #[inline(always)] fn from_seed(seed: Self::Seed) -> Self {