From aee9a7b81284345c32fcee11da339a324c2cdcb4 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 3 May 2018 19:54:46 +0200 Subject: [PATCH] Move all *Rng wrappers to rngs dir --- src/distributions/float.rs | 2 +- src/distributions/mod.rs | 2 +- src/lib.rs | 472 +++++++++++------------- src/{entropy_rng.rs => rngs/entropy.rs} | 5 +- src/{ => rngs}/jitter.rs | 0 src/{ => rngs}/mock.rs | 2 +- src/rngs/mod.rs | 33 ++ src/{ => rngs}/os.rs | 0 src/{ => rngs}/read.rs | 0 src/{ => rngs}/reseeding.rs | 2 +- src/rngs/small.rs | 99 +++++ src/rngs/std.rs | 83 +++++ src/{thread_rng.rs => rngs/thread.rs} | 103 +----- 13 files changed, 451 insertions(+), 352 deletions(-) rename src/{entropy_rng.rs => rngs/entropy.rs} (98%) rename src/{ => rngs}/jitter.rs (100%) rename src/{ => rngs}/mock.rs (98%) create mode 100644 src/rngs/mod.rs rename src/{ => rngs}/os.rs (100%) rename src/{ => rngs}/read.rs (100%) rename src/{ => rngs}/reseeding.rs (99%) create mode 100644 src/rngs/small.rs create mode 100644 src/rngs/std.rs rename src/{thread_rng.rs => rngs/thread.rs} (52%) diff --git a/src/distributions/float.rs b/src/distributions/float.rs index 6db9b6d2aed..83af82984b4 100644 --- a/src/distributions/float.rs +++ b/src/distributions/float.rs @@ -148,7 +148,7 @@ float_impls! { f64, u64, 52, 1023 } mod tests { use Rng; use distributions::{Open01, OpenClosed01}; - use mock::StepRng; + use rngs::mock::StepRng; const EPSILON32: f32 = ::core::f32::EPSILON; const EPSILON64: f64 = ::core::f64::EPSILON; diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index e68b2ff9830..3568ad77e57 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -479,7 +479,7 @@ fn ziggurat( #[cfg(test)] mod tests { use Rng; - use mock::StepRng; + use rngs::mock::StepRng; use super::{WeightedChoice, Weighted, Distribution}; #[test] diff --git a/src/lib.rs b/src/lib.rs index 5f6fae21d83..b09d9f4ac28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,12 +149,12 @@ //! [`from_rng`]: trait.SeedableRng.html#method.from_rng //! [`CryptoRng`]: trait.CryptoRng.html //! [`thread_rng`]: fn.thread_rng.html -//! [`EntropyRng`]: struct.EntropyRng.html +//! [`EntropyRng`]: rngs/struct.EntropyRng.html //! [`OsRng`]: os/struct.OsRng.html //! [`JitterRng`]: jitter/struct.JitterRng.html //! [`StdRng`]: struct.StdRng.html //! [`SmallRng`]: struct.SmallRng.html -//! [`ReseedingRng`]: reseeding/struct.ReseedingRng.html +//! [`ReseedingRng`]: rngs/struct.ReseedingRng.html //! [`prng`]: prng/index.html //! [`IsaacRng::new_from_u64`]: prng/isaac/struct.IsaacRng.html#method.new_from_u64 //! [`Hc128Rng`]: prng/hc128/struct.Hc128Rng.html @@ -204,26 +204,23 @@ extern crate rand_core; pub use rand_core::{RngCore, BlockRngCore, CryptoRng, SeedableRng}; pub use rand_core::{ErrorKind, Error}; -// Public exports -#[cfg(feature="std")] pub use entropy_rng::EntropyRng; -#[cfg(feature="std")] pub use os::OsRng; -pub use reseeding::ReseedingRng; -#[cfg(feature="std")] pub use thread_rng::{ThreadRng, thread_rng}; -#[cfg(feature="std")] #[allow(deprecated)] pub use thread_rng::random; - // Public modules pub mod distributions; -pub mod jitter; // Public because of the error type. -pub mod mock; // Public so we don't export `StepRng` directly, making it a bit - // more clear it is intended for testing. pub mod prng; -#[cfg(feature="std")] pub mod read; +pub mod rngs; #[cfg(feature = "alloc")] pub mod seq; +pub use rngs::SmallRng; +pub use rngs::StdRng; + +//////////////////////////////////////////////////////////////////////////////// +// Compatibility re-exports + // These modules are public to avoid API breakage, probably only temporarily. // Hidden in the documentation. -#[cfg(feature="std")] #[doc(hidden)] pub mod os; + #[doc(hidden)] pub use prng::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; + #[doc(hidden)] pub mod chacha { //! The ChaCha random number generator. @@ -235,33 +232,38 @@ pub mod isaac { pub use prng::{IsaacRng, Isaac64Rng}; } -// private modules -#[cfg(feature="std")] mod entropy_rng; -mod reseeding; -#[cfg(feature="std")] mod thread_rng; +#[cfg(feature="std")] +#[doc(hidden)] pub use rngs::{EntropyRng, OsRng, ReadRng, ThreadRng}; +#[doc(hidden)] pub use rngs::{JitterRng, ReseedingRng}; + +#[doc(hidden)] +#[cfg(feature="std")] +pub mod os { + //! Interface to the operating system provided random number generators. + pub use rngs::OsRng; +} + +#[doc(hidden)] +#[cfg(feature="std")] +pub mod read { + //! A wrapper around any Read to treat it as an RNG. + pub use rngs::ReadRng; +} + +#[doc(hidden)] +pub mod jitter { + //! A wrapper around any Read to treat it as an RNG. + pub use rngs::{JitterRng, TimerError}; +} + +//////////////////////////////////////////////////////////////////////////////// -// Normal imports just for this file use core::{marker, mem, slice}; use distributions::{Distribution, Standard, Uniform}; use distributions::uniform::SampleUniform; -use prng::hc128::Hc128Rng; -/// A type that can be randomly generated using an [`Rng`]. -/// -/// This is merely an adaptor around the [`Standard`] distribution for -/// convenience and backwards-compatibility. -/// -/// [`Rng`]: trait.Rng.html -/// [`Standard`]: distributions/struct.Standard.html -#[deprecated(since="0.5.0", note="replaced by distributions::Standard")] -pub trait Rand : Sized { - /// Generates a random instance of this type using the specified source of - /// randomness. - fn rand(rng: &mut R) -> Self; -} - /// An automatically-implemented extension trait on [`RngCore`] providing high-level /// generic methods for sampling values and other convenience methods. /// @@ -616,6 +618,155 @@ pub trait Rng: RngCore { impl Rng for R {} + +/// A convenience extension to [`SeedableRng`] allowing construction from fresh +/// entropy. This trait is automatically implemented for any PRNG implementing +/// [`SeedableRng`] and is not intended to be implemented by users. +/// +/// This is equivalent to using `SeedableRng::from_rng(EntropyRng::new())` then +/// unwrapping the result. +/// +/// Since this is convenient and secure, it is the recommended way to create +/// PRNGs, though two alternatives may be considered: +/// +/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed +/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`; +/// this will usually be faster and should also be secure, but requires +/// trusting one extra component. +/// +/// ## Example +/// +/// ``` +/// use rand::{StdRng, Rng, FromEntropy}; +/// +/// let mut rng = StdRng::from_entropy(); +/// println!("Random die roll: {}", rng.gen_range(1, 7)); +/// ``` +/// +/// [`EntropyRng`]: rngs/struct.EntropyRng.html +/// [`SeedableRng`]: trait.SeedableRng.html +/// [`SeedableRng::from_seed`]: trait.SeedableRng.html#tymethod.from_seed +#[cfg(feature="std")] +pub trait FromEntropy: SeedableRng { + /// Creates a new instance, automatically seeded with fresh entropy. + /// + /// Normally this will use `OsRng`, but if that fails `JitterRng` will be + /// used instead. Both should be suitable for cryptography. It is possible + /// that both entropy sources will fail though unlikely; failures would + /// almost certainly be platform limitations or build issues, i.e. most + /// applications targetting PC/mobile platforms should not need to worry + /// about this failing. + /// + /// If all entropy sources fail this will panic. If you need to handle + /// errors, use the following code, equivalent aside from error handling: + /// + /// ```rust + /// # use rand::Error; + /// use rand::{Rng, StdRng, EntropyRng, SeedableRng}; + /// + /// # fn try_inner() -> Result<(), Error> { + /// // This uses StdRng, but is valid for any R: SeedableRng + /// let mut rng = StdRng::from_rng(EntropyRng::new())?; + /// + /// println!("random number: {}", rng.gen_range(1, 10)); + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + fn from_entropy() -> Self; +} + +#[cfg(feature="std")] +impl FromEntropy for R { + fn from_entropy() -> R { + R::from_rng(EntropyRng::new()).unwrap_or_else(|err| + panic!("FromEntropy::from_entropy() failed: {}", err)) + } +} + +/// Generates a random value using the thread-local random number generator. +/// +/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for +/// documentation of the entropy source and [`Standard`] for documentation of +/// distributions and type-specific generation. +/// +/// # Examples +/// +/// ``` +/// let x = rand::random::(); +/// println!("{}", x); +/// +/// let y = rand::random::(); +/// println!("{}", y); +/// +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); +/// } +/// ``` +/// +/// If you're calling `random()` in a loop, caching the generator as in the +/// following example can increase performance. +/// +/// ``` +/// # #![allow(deprecated)] +/// use rand::Rng; +/// +/// let mut v = vec![1, 2, 3]; +/// +/// for x in v.iter_mut() { +/// *x = rand::random() +/// } +/// +/// // can be made faster by caching thread_rng +/// +/// let mut rng = rand::thread_rng(); +/// +/// for x in v.iter_mut() { +/// *x = rng.gen(); +/// } +/// ``` +/// +/// [`thread_rng`]: fn.thread_rng.html +/// [`Standard`]: distributions/struct.Standard.html +#[cfg(feature="std")] +#[inline] +pub fn random() -> T where Standard: Distribution { + thread_rng().gen() +} + +/// Retrieve the lazily-initialized thread-local random number +/// generator, seeded by the system. Intended to be used in method +/// chaining style, e.g. `thread_rng().gen::()`, or cached locally, e.g. +/// `let mut rng = thread_rng();`. +/// +/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`], +/// which is reseeded after generating 32 MiB of random data. A single instance +/// is cached per thread and the returned `ThreadRng` is a reference to this +/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use +/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`] +/// as required. +/// +/// Note that the reseeding is done as an extra precaution against entropy +/// leaks and is in theory unnecessary — to predict `thread_rng`'s output, an +/// attacker would have to either determine most of the RNG's seed or internal +/// state, or crack the algorithm used. +/// +/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current +/// algorithm used is [HC-128], which is an array-based PRNG that trades memory +/// usage for better performance. This makes it similar to ISAAC, the algorithm +/// used in `ThreadRng` before rand 0.5. +/// +/// [`ReseedingRng`]: rngs/struct.ReseedingRng.html +/// [`StdRng`]: struct.StdRng.html +/// [`EntropyRng`]: rngs/struct.EntropyRng.html +/// [HC-128]: prng/hc128/struct.Hc128Rng.html +#[cfg(feature="std")] +pub fn thread_rng() -> ThreadRng { + ThreadRng::new() +} + + /// Trait for casting types to byte slices /// /// This is used by the [`fill`] and [`try_fill`] methods. @@ -705,6 +856,28 @@ macro_rules! impl_as_byte_slice_arrays { impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,); impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,); + + +//////////////////////////////////////////////////////////////////////////////// +// +// DEPRECATED FUNCTIONALITY +// +//////////////////////////////////////////////////////////////////////////////// + +/// A type that can be randomly generated using an [`Rng`]. +/// +/// This is merely an adaptor around the [`Standard`] distribution for +/// convenience and backwards-compatibility. +/// +/// [`Rng`]: trait.Rng.html +/// [`Standard`]: distributions/struct.Standard.html +#[deprecated(since="0.5.0", note="replaced by distributions::Standard")] +pub trait Rand : Sized { + /// Generates a random instance of this type using the specified source of + /// randomness. + fn rand(rng: &mut R) -> Self; +} + /// Iterator which will generate a stream of random items. /// /// This iterator is created via the [`gen_iter`] method on [`Rng`]. @@ -754,209 +927,6 @@ impl Iterator for AsciiGenerator { } } - -/// A convenience extension to [`SeedableRng`] allowing construction from fresh -/// entropy. This trait is automatically implemented for any PRNG implementing -/// [`SeedableRng`] and is not intended to be implemented by users. -/// -/// This is equivalent to using `SeedableRng::from_rng(EntropyRng::new())` then -/// unwrapping the result. -/// -/// Since this is convenient and secure, it is the recommended way to create -/// PRNGs, though two alternatives may be considered: -/// -/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed -/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`; -/// this will usually be faster and should also be secure, but requires -/// trusting one extra component. -/// -/// ## Example -/// -/// ``` -/// use rand::{StdRng, Rng, FromEntropy}; -/// -/// let mut rng = StdRng::from_entropy(); -/// println!("Random die roll: {}", rng.gen_range(1, 7)); -/// ``` -/// -/// [`EntropyRng`]: struct.EntropyRng.html -/// [`SeedableRng`]: trait.SeedableRng.html -/// [`SeedableRng::from_seed`]: trait.SeedableRng.html#tymethod.from_seed -#[cfg(feature="std")] -pub trait FromEntropy: SeedableRng { - /// Creates a new instance, automatically seeded with fresh entropy. - /// - /// Normally this will use `OsRng`, but if that fails `JitterRng` will be - /// used instead. Both should be suitable for cryptography. It is possible - /// that both entropy sources will fail though unlikely; failures would - /// almost certainly be platform limitations or build issues, i.e. most - /// applications targetting PC/mobile platforms should not need to worry - /// about this failing. - /// - /// If all entropy sources fail this will panic. If you need to handle - /// errors, use the following code, equivalent aside from error handling: - /// - /// ```rust - /// # use rand::Error; - /// use rand::{Rng, StdRng, EntropyRng, SeedableRng}; - /// - /// # fn try_inner() -> Result<(), Error> { - /// // This uses StdRng, but is valid for any R: SeedableRng - /// let mut rng = StdRng::from_rng(EntropyRng::new())?; - /// - /// println!("random number: {}", rng.gen_range(1, 10)); - /// # Ok(()) - /// # } - /// - /// # try_inner().unwrap() - /// ``` - fn from_entropy() -> Self; -} - -#[cfg(feature="std")] -impl FromEntropy for R { - fn from_entropy() -> R { - R::from_rng(EntropyRng::new()).unwrap_or_else(|err| - panic!("FromEntropy::from_entropy() failed: {}", err)) - } -} - -/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient -/// on the current platform, to be statistically strong and unpredictable -/// (meaning a cryptographically secure PRNG). -/// -/// The current algorithm used on all platforms is [HC-128]. -/// -/// Reproducibility of output from this generator is however not required, thus -/// future library versions may use a different internal generator with -/// different output. Further, this generator may not be portable and can -/// produce different output depending on the architecture. If you require -/// reproducible output, use a named RNG, for example [`ChaChaRng`]. -/// -/// [HC-128]: prng/hc128/struct.Hc128Rng.html -/// [`ChaChaRng`]: prng/chacha/struct.ChaChaRng.html -#[derive(Clone, Debug)] -pub struct StdRng(Hc128Rng); - -impl RngCore for StdRng { - #[inline(always)] - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - - 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 SeedableRng for StdRng { - type Seed = ::Seed; - - fn from_seed(seed: Self::Seed) -> Self { - StdRng(Hc128Rng::from_seed(seed)) - } - - fn from_rng(rng: R) -> Result { - Hc128Rng::from_rng(rng).map(StdRng) - } -} - -impl CryptoRng for StdRng {} - -/// An RNG recommended when small state, cheap initialization and good -/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be -/// efficient on the current platform, **without consideration for cryptography -/// or security**. The size of its state is much smaller than for [`StdRng`]. -/// -/// Reproducibility of output from this generator is however not required, thus -/// future library versions may use a different internal generator with -/// different output. Further, this generator may not be portable and can -/// produce different output depending on the architecture. If you require -/// reproducible output, use a named RNG, for example [`XorShiftRng`]. -/// -/// The current algorithm used on all platforms is [Xorshift]. -/// -/// # Examples -/// -/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: -/// -/// ``` -/// # use rand::Rng; -/// use rand::{FromEntropy, 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 std::iter; -/// use rand::{SeedableRng, SmallRng, thread_rng}; -/// -/// // 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 = iter::repeat(()) -/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) -/// .take(10) -/// .collect(); -/// ``` -/// -/// [`FromEntropy`]: trait.FromEntropy.html -/// [`StdRng`]: struct.StdRng.html -/// [`thread_rng`]: fn.thread_rng.html -/// [Xorshift]: prng/struct.XorShiftRng.html -/// [`XorShiftRng`]: prng/struct.XorShiftRng.html -#[derive(Clone, Debug)] -pub struct SmallRng(XorShiftRng); - -impl RngCore for SmallRng { - #[inline(always)] - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - - 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 SeedableRng for SmallRng { - type Seed = ::Seed; - - fn from_seed(seed: Self::Seed) -> Self { - SmallRng(XorShiftRng::from_seed(seed)) - } - - fn from_rng(rng: R) -> Result { - XorShiftRng::from_rng(rng).map(SmallRng) - } -} - /// DEPRECATED: use [`SmallRng`] instead. /// /// Create a weak random number generator with a default algorithm and seed. @@ -1005,7 +975,7 @@ pub fn sample(rng: &mut R, iterable: I, amount: usize) -> Vec #[cfg(test)] mod test { - use mock::StepRng; + use rngs::mock::StepRng; use super::*; #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box; @@ -1044,6 +1014,21 @@ mod test { TestRng { inner: StdRng::from_seed(seed) } } + #[test] + #[cfg(feature="std")] + fn test_random() { + // not sure how to test this aside from just getting some values + let _n : usize = random(); + let _f : f32 = random(); + let _o : Option> = random(); + let _many : ((), + (usize, + isize, + Option<(u32, (bool,))>), + (u8, i8, u16, i16, u32, i32, u64, i64), + (f32, (f64, (f64,)))) = random(); + } + #[test] fn test_fill_bytes_default() { let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0); @@ -1192,15 +1177,4 @@ mod test { assert_eq!(r.gen_range(0, 1), 0); let _c: u8 = Standard.sample(&mut r); } - - #[test] - fn test_stdrng_construction() { - let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; - let mut rng1 = StdRng::from_seed(seed); - assert_eq!(rng1.next_u64(), 15759097995037006553); - - let mut rng2 = StdRng::from_rng(rng1).unwrap(); - assert_eq!(rng2.next_u64(), 6766915756997287454); - } } diff --git a/src/entropy_rng.rs b/src/rngs/entropy.rs similarity index 98% rename from src/entropy_rng.rs rename to src/rngs/entropy.rs index 6b31fc641a2..855cab0053b 100644 --- a/src/entropy_rng.rs +++ b/src/rngs/entropy.rs @@ -11,8 +11,7 @@ //! Entropy generator, or wrapper around external generators use rand_core::{RngCore, CryptoRng, Error, impls}; -use os::OsRng; -use jitter::JitterRng; +use {OsRng, JitterRng}; /// An interface returning random data from external source(s), provided /// specifically for securely seeding algorithmic generators (PRNGs). @@ -33,7 +32,7 @@ use jitter::JitterRng; /// /// [`OsRng`]: os/struct.OsRng.html /// [`JitterRng`]: jitter/struct.JitterRng.html -/// [`thread_rng`]: fn.thread_rng.html +/// [`thread_rng`]: ../fn.thread_rng.html #[derive(Debug)] pub struct EntropyRng { rng: EntropySource, diff --git a/src/jitter.rs b/src/rngs/jitter.rs similarity index 100% rename from src/jitter.rs rename to src/rngs/jitter.rs diff --git a/src/mock.rs b/src/rngs/mock.rs similarity index 98% rename from src/mock.rs rename to src/rngs/mock.rs index 090258ef8b2..3651e04776b 100644 --- a/src/mock.rs +++ b/src/rngs/mock.rs @@ -20,7 +20,7 @@ use rand_core::{RngCore, Error, impls}; /// /// ```rust /// use rand::Rng; -/// use rand::mock::StepRng; +/// use rand::rngs::mock::StepRng; /// /// let mut my_rng = StepRng::new(2, 1); /// let sample: [u64; 3] = my_rng.gen(); diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs new file mode 100644 index 00000000000..e38955c3c6e --- /dev/null +++ b/src/rngs/mod.rs @@ -0,0 +1,33 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Various RNGs and wrappers. + +#[cfg(feature="std")] mod entropy; +mod jitter; +pub mod mock; +#[cfg(feature="std")] mod os; +#[cfg(feature="std")] mod read; +mod reseeding; +mod small; +mod std; +#[cfg(feature="std")] mod thread; + +// Sources of external randomness +#[cfg(feature="std")] pub use self::entropy::EntropyRng; +pub use self::jitter::{JitterRng, TimerError}; +#[cfg(feature="std")] pub use self::os::OsRng; + +// Wrappers +#[cfg(feature="std")] pub use self::read::ReadRng; +pub use self::reseeding::ReseedingRng; +#[doc(hidden)] pub use self::small::SmallRng; +#[doc(hidden)] pub use self::std::StdRng; +#[cfg(feature="std")] pub use self::thread::ThreadRng; diff --git a/src/os.rs b/src/rngs/os.rs similarity index 100% rename from src/os.rs rename to src/rngs/os.rs diff --git a/src/read.rs b/src/rngs/read.rs similarity index 100% rename from src/read.rs rename to src/rngs/read.rs diff --git a/src/reseeding.rs b/src/rngs/reseeding.rs similarity index 99% rename from src/reseeding.rs rename to src/rngs/reseeding.rs index 4af5fa2ac2e..86e20c9a65d 100644 --- a/src/reseeding.rs +++ b/src/rngs/reseeding.rs @@ -224,7 +224,7 @@ where R: BlockRngCore + SeedableRng + CryptoRng, mod test { use {Rng, SeedableRng}; use prng::chacha::ChaChaCore; - use mock::StepRng; + use rngs::mock::StepRng; use super::ReseedingRng; #[test] diff --git a/src/rngs/small.rs b/src/rngs/small.rs new file mode 100644 index 00000000000..226bcfbdca2 --- /dev/null +++ b/src/rngs/small.rs @@ -0,0 +1,99 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A small fast RNG + +use {RngCore, SeedableRng, Error}; +use prng::XorShiftRng; + +/// An RNG recommended when small state, cheap initialization and good +/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be +/// efficient on the current platform, **without consideration for cryptography +/// or security**. The size of its state is much smaller than for [`StdRng`]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`XorShiftRng`]. +/// +/// The current algorithm used on all platforms is [Xorshift]. +/// +/// # Examples +/// +/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: +/// +/// ``` +/// # use rand::Rng; +/// use rand::{FromEntropy, 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 std::iter; +/// use rand::{SeedableRng, SmallRng, thread_rng}; +/// +/// // 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 = iter::repeat(()) +/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) +/// .take(10) +/// .collect(); +/// ``` +/// +/// [`FromEntropy`]: trait.FromEntropy.html +/// [`StdRng`]: struct.StdRng.html +/// [`thread_rng`]: fn.thread_rng.html +/// [Xorshift]: prng/struct.XorShiftRng.html +/// [`XorShiftRng`]: prng/struct.XorShiftRng.html +#[derive(Clone, Debug)] +pub struct SmallRng(XorShiftRng); + +impl RngCore for SmallRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + 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 SeedableRng for SmallRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + SmallRng(XorShiftRng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + XorShiftRng::from_rng(rng).map(SmallRng) + } +} diff --git a/src/rngs/std.rs b/src/rngs/std.rs new file mode 100644 index 00000000000..70d3c9d3fc9 --- /dev/null +++ b/src/rngs/std.rs @@ -0,0 +1,83 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The standard RNG + +use {RngCore, CryptoRng, Error, SeedableRng}; +use prng::Hc128Rng; + +/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient +/// on the current platform, to be statistically strong and unpredictable +/// (meaning a cryptographically secure PRNG). +/// +/// The current algorithm used on all platforms is [HC-128]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`ChaChaRng`]. +/// +/// [HC-128]: prng/hc128/struct.Hc128Rng.html +/// [`ChaChaRng`]: prng/chacha/struct.ChaChaRng.html +#[derive(Clone, Debug)] +pub struct StdRng(Hc128Rng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + 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 SeedableRng for StdRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(Hc128Rng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + Hc128Rng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use rngs::StdRng; + + #[test] + fn test_stdrng_construction() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = StdRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 15759097995037006553); + + let mut rng2 = StdRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 6766915756997287454); + } +} diff --git a/src/thread_rng.rs b/src/rngs/thread.rs similarity index 52% rename from src/thread_rng.rs rename to src/rngs/thread.rs index 09b5a39b690..ad18dcf3f04 100644 --- a/src/thread_rng.rs +++ b/src/rngs/thread.rs @@ -13,10 +13,8 @@ use std::cell::UnsafeCell; use std::rc::Rc; -use {RngCore, CryptoRng, SeedableRng, EntropyRng}; +use {RngCore, CryptoRng, SeedableRng, EntropyRng, ReseedingRng, Error}; use prng::hc128::Hc128Core; -use {Distribution, Standard, Rng, Error}; -use reseeding::ReseedingRng; // Rationale for using `UnsafeCell` in `ThreadRng`: // @@ -50,7 +48,7 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB /// Cloning this handle just produces a new reference to the same thread-local /// generator. /// -/// [`thread_rng`]: fn.thread_rng.html +/// [`thread_rng`]: ../fn.thread_rng.html #[derive(Clone, Debug)] pub struct ThreadRng { rng: Rc>>, @@ -68,34 +66,11 @@ thread_local!( } ); -/// Retrieve the lazily-initialized thread-local random number -/// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `thread_rng().gen::()`, or cached locally, e.g. -/// `let mut rng = thread_rng();`. -/// -/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`], -/// which is reseeded after generating 32 MiB of random data. A single instance -/// is cached per thread and the returned `ThreadRng` is a reference to this -/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use -/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`] -/// as required. -/// -/// Note that the reseeding is done as an extra precaution against entropy -/// leaks and is in theory unnecessary — to predict `thread_rng`'s output, an -/// attacker would have to either determine most of the RNG's seed or internal -/// state, or crack the algorithm used. -/// -/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current -/// algorithm used is [HC-128], which is an array-based PRNG that trades memory -/// usage for better performance. This makes it similar to ISAAC, the algorithm -/// used in `ThreadRng` before rand 0.5. -/// -/// [`ReseedingRng`]: reseeding/struct.ReseedingRng.html -/// [`StdRng`]: struct.StdRng.html -/// [`EntropyRng`]: struct.EntropyRng.html -/// [HC-128]: prng/hc128/struct.Hc128Rng.html -pub fn thread_rng() -> ThreadRng { - ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } +impl ThreadRng { + /// Get a reference to the thread-local random number. + pub(crate) fn new() -> ThreadRng { + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } + } } impl RngCore for ThreadRng { @@ -120,54 +95,6 @@ impl RngCore for ThreadRng { impl CryptoRng for ThreadRng {} -/// Generates a random value using the thread-local random number generator. -/// -/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for -/// documentation of the entropy source and [`Standard`] for documentation of -/// distributions and type-specific generation. -/// -/// # Examples -/// -/// ```rust -/// let x = rand::random::(); -/// println!("{}", x); -/// -/// let y = rand::random::(); -/// println!("{}", y); -/// -/// if rand::random() { // generates a boolean -/// println!("Better lucky than good!"); -/// } -/// ``` -/// -/// If you're calling `random()` in a loop, caching the generator as in the -/// following example can increase performance. -/// -/// ```rust -/// # #![allow(deprecated)] -/// use rand::Rng; -/// -/// let mut v = vec![1, 2, 3]; -/// -/// for x in v.iter_mut() { -/// *x = rand::random() -/// } -/// -/// // can be made faster by caching thread_rng -/// -/// let mut rng = rand::thread_rng(); -/// -/// for x in v.iter_mut() { -/// *x = rng.gen(); -/// } -/// ``` -/// -/// [`thread_rng`]: fn.thread_rng.html -/// [`Standard`]: distributions/struct.Standard.html -#[inline] -pub fn random() -> T where Standard: Distribution { - thread_rng().gen() -} #[cfg(test)] mod test { @@ -183,20 +110,4 @@ mod test { assert_eq!(v, b); assert_eq!(r.gen_range(0, 1), 0); } - - #[test] - #[allow(deprecated)] - fn test_random() { - use super::random; - // not sure how to test this aside from just getting some values - let _n : usize = random(); - let _f : f32 = random(); - let _o : Option> = random(); - let _many : ((), - (usize, - isize, - Option<(u32, (bool,))>), - (u8, i8, u16, i16, u32, i32, u64, i64), - (f32, (f64, (f64,)))) = random(); - } }