diff options
Diffstat (limited to 'rand/src/rngs')
-rw-r--r-- | rand/src/rngs/adapter/mod.rs | 15 | ||||
-rw-r--r-- | rand/src/rngs/adapter/read.rs | 148 | ||||
-rw-r--r-- | rand/src/rngs/adapter/reseeding.rs | 357 | ||||
-rw-r--r-- | rand/src/rngs/entropy.rs | 76 | ||||
-rw-r--r-- | rand/src/rngs/mock.rs | 64 | ||||
-rw-r--r-- | rand/src/rngs/mod.rs | 119 | ||||
-rw-r--r-- | rand/src/rngs/small.rs | 115 | ||||
-rw-r--r-- | rand/src/rngs/std.rs | 100 | ||||
-rw-r--r-- | rand/src/rngs/thread.rs | 124 |
9 files changed, 0 insertions, 1118 deletions
diff --git a/rand/src/rngs/adapter/mod.rs b/rand/src/rngs/adapter/mod.rs deleted file mode 100644 index 659ff26..0000000 --- a/rand/src/rngs/adapter/mod.rs +++ /dev/null @@ -1,15 +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. - -//! Wrappers / adapters forming RNGs - -#[cfg(feature="std")] mod read; -mod reseeding; - -#[cfg(feature="std")] pub use self::read::{ReadRng, ReadError}; -pub use self::reseeding::ReseedingRng; diff --git a/rand/src/rngs/adapter/read.rs b/rand/src/rngs/adapter/read.rs deleted file mode 100644 index 901462e..0000000 --- a/rand/src/rngs/adapter/read.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2013 The Rust Project Developers. -// -// 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. - -//! A wrapper around any Read to treat it as an RNG. - -use std::io::Read; -use std::fmt; - -use rand_core::{RngCore, Error, impls}; - - -/// An RNG that reads random bytes straight from any type supporting -/// [`std::io::Read`], for example files. -/// -/// This will work best with an infinite reader, but that is not required. -/// -/// This can be used with `/dev/urandom` on Unix but it is recommended to use -/// [`OsRng`] instead. -/// -/// # Panics -/// -/// `ReadRng` uses [`std::io::Read::read_exact`], which retries on interrupts. -/// All other errors from the underlying reader, including when it does not -/// have enough data, will only be reported through [`try_fill_bytes`]. -/// The other [`RngCore`] methods will panic in case of an error. -/// -/// # Example -/// -/// ``` -/// use rand::Rng; -/// use rand::rngs::adapter::ReadRng; -/// -/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8]; -/// let mut rng = ReadRng::new(&data[..]); -/// println!("{:x}", rng.gen::<u32>()); -/// ``` -/// -/// [`OsRng`]: crate::rngs::OsRng -/// [`try_fill_bytes`]: RngCore::try_fill_bytes -#[derive(Debug)] -pub struct ReadRng<R> { - reader: R -} - -impl<R: Read> ReadRng<R> { - /// Create a new `ReadRng` from a `Read`. - pub fn new(r: R) -> ReadRng<R> { - ReadRng { - reader: r - } - } -} - -impl<R: Read> RngCore for ReadRng<R> { - fn next_u32(&mut self) -> u32 { - impls::next_u32_via_fill(self) - } - - fn next_u64(&mut self) -> u64 { - impls::next_u64_via_fill(self) - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.try_fill_bytes(dest).unwrap_or_else(|err| - panic!("reading random bytes from Read implementation failed; error: {}", err)); - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - if dest.is_empty() { return Ok(()); } - // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. - self.reader.read_exact(dest).map_err(|e| Error::new(ReadError(e))) - } -} - -/// `ReadRng` error type -#[derive(Debug)] -pub struct ReadError(std::io::Error); - -impl fmt::Display for ReadError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ReadError: {}", self.0) - } -} - -impl std::error::Error for ReadError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(&self.0) - } -} - - -#[cfg(test)] -mod test { - use super::ReadRng; - use crate::RngCore; - - #[test] - fn test_reader_rng_u64() { - // transmute from the target to avoid endianness concerns. - let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1, - 0 , 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 3]; - let mut rng = ReadRng::new(&v[..]); - - assert_eq!(rng.next_u64(), 1_u64.to_be()); - assert_eq!(rng.next_u64(), 2_u64.to_be()); - assert_eq!(rng.next_u64(), 3_u64.to_be()); - } - - #[test] - fn test_reader_rng_u32() { - let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; - let mut rng = ReadRng::new(&v[..]); - - assert_eq!(rng.next_u32(), 1_u32.to_be()); - assert_eq!(rng.next_u32(), 2_u32.to_be()); - assert_eq!(rng.next_u32(), 3_u32.to_be()); - } - - #[test] - fn test_reader_rng_fill_bytes() { - let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let mut w = [0u8; 8]; - - let mut rng = ReadRng::new(&v[..]); - rng.fill_bytes(&mut w); - - assert!(v == w); - } - - #[test] - fn test_reader_rng_insufficient_bytes() { - let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let mut w = [0u8; 9]; - - let mut rng = ReadRng::new(&v[..]); - - let result = rng.try_fill_bytes(&mut w); - assert!(result.is_err()); - println!("Error: {}", result.unwrap_err()); - } -} diff --git a/rand/src/rngs/adapter/reseeding.rs b/rand/src/rngs/adapter/reseeding.rs deleted file mode 100644 index ec88efe..0000000 --- a/rand/src/rngs/adapter/reseeding.rs +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2013 The Rust Project Developers. -// -// 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. - -//! A wrapper around another PRNG that reseeds it after it -//! generates a certain number of random bytes. - -use core::mem::size_of; - -use rand_core::{RngCore, CryptoRng, SeedableRng, Error}; -use rand_core::block::{BlockRngCore, BlockRng}; - -/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the -/// ability to reseed it. -/// -/// `ReseedingRng` reseeds the underlying PRNG in the following cases: -/// -/// - On a manual call to [`reseed()`]. -/// - After `clone()`, the clone will be reseeded on first use. -/// - After a process is forked, the RNG in the child process is reseeded within -/// the next few generated values, depending on the block size of the -/// underlying PRNG. For ChaCha and Hc128 this is a maximum of -/// 15 `u32` values before reseeding. -/// - After the PRNG has generated a configurable number of random bytes. -/// -/// # When should reseeding after a fixed number of generated bytes be used? -/// -/// Reseeding after a fixed number of generated bytes is never strictly -/// *necessary*. Cryptographic PRNGs don't have a limited number of bytes they -/// can output, or at least not a limit reachable in any practical way. There is -/// no such thing as 'running out of entropy'. -/// -/// Occasionally reseeding can be seen as some form of 'security in depth'. Even -/// if in the future a cryptographic weakness is found in the CSPRNG being used, -/// or a flaw in the implementation, occasionally reseeding should make -/// exploiting it much more difficult or even impossible. -/// -/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding -/// after a fixed number of generated bytes. -/// -/// # Error handling -/// -/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will -/// never panic but try to handle the error intelligently through some -/// combination of retrying and delaying reseeding until later. -/// If handling the source error fails `ReseedingRng` will continue generating -/// data from the wrapped PRNG without reseeding. -/// -/// Manually calling [`reseed()`] will not have this retry or delay logic, but -/// reports the error. -/// -/// # Example -/// -/// ``` -/// use rand::prelude::*; -/// use rand_chacha::ChaCha20Core; // Internal part of ChaChaRng that -/// // implements BlockRngCore -/// use rand::rngs::OsRng; -/// use rand::rngs::adapter::ReseedingRng; -/// -/// let prng = ChaCha20Core::from_entropy(); -/// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng); -/// -/// println!("{}", reseeding_rng.gen::<u64>()); -/// -/// let mut cloned_rng = reseeding_rng.clone(); -/// assert!(reseeding_rng.gen::<u64>() != cloned_rng.gen::<u64>()); -/// ``` -/// -/// [`BlockRngCore`]: rand_core::block::BlockRngCore -/// [`ReseedingRng::new`]: ReseedingRng::new -/// [`reseed()`]: ReseedingRng::reseed -#[derive(Debug)] -pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>) -where R: BlockRngCore + SeedableRng, - Rsdr: RngCore; - -impl<R, Rsdr> ReseedingRng<R, Rsdr> -where R: BlockRngCore + SeedableRng, - Rsdr: RngCore -{ - /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG - /// to use as reseeder. - /// - /// `threshold` sets the number of generated bytes after which to reseed the - /// PRNG. Set it to zero to never reseed based on the number of generated - /// values. - pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { - ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder))) - } - - /// Reseed the internal PRNG. - pub fn reseed(&mut self) -> Result<(), Error> { - self.0.core.reseed() - } -} - -// 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> -where R: BlockRngCore<Item = u32> + SeedableRng, - <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]> -{ - #[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<R, Rsdr> Clone for ReseedingRng<R, Rsdr> -where R: BlockRngCore + SeedableRng + Clone, - Rsdr: RngCore + Clone -{ - fn clone(&self) -> ReseedingRng<R, Rsdr> { - // Recreating `BlockRng` seems easier than cloning it and resetting - // the index. - ReseedingRng(BlockRng::new(self.0.core.clone())) - } -} - -impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr> -where R: BlockRngCore + SeedableRng + CryptoRng, - Rsdr: RngCore + CryptoRng {} - -#[derive(Debug)] -struct ReseedingCore<R, Rsdr> { - inner: R, - reseeder: Rsdr, - threshold: i64, - bytes_until_reseed: i64, - fork_counter: usize, -} - -impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr> -where R: BlockRngCore + SeedableRng, - Rsdr: RngCore -{ - type Item = <R as BlockRngCore>::Item; - type Results = <R as BlockRngCore>::Results; - - fn generate(&mut self, results: &mut Self::Results) { - let global_fork_counter = fork::get_fork_counter(); - if self.bytes_until_reseed <= 0 || - self.is_forked(global_fork_counter) { - // We get better performance by not calling only `reseed` here - // and continuing with the rest of the function, but by directly - // returning from a non-inlined function. - return self.reseed_and_generate(results, global_fork_counter); - } - let num_bytes = results.as_ref().len() * size_of::<Self::Item>(); - self.bytes_until_reseed -= num_bytes as i64; - self.inner.generate(results); - } -} - -impl<R, Rsdr> ReseedingCore<R, Rsdr> -where R: BlockRngCore + SeedableRng, - Rsdr: RngCore -{ - /// Create a new `ReseedingCore`. - fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { - use ::core::i64::MAX; - fork::register_fork_handler(); - - // Because generating more values than `i64::MAX` takes centuries on - // current hardware, we just clamp to that value. - // Also we set a threshold of 0, which indicates no limit, to that - // value. - let threshold = - if threshold == 0 { MAX } - else if threshold <= MAX as u64 { threshold as i64 } - else { MAX }; - - ReseedingCore { - inner: rng, - reseeder, - threshold: threshold as i64, - bytes_until_reseed: threshold as i64, - fork_counter: 0, - } - } - - /// Reseed the internal PRNG. - fn reseed(&mut self) -> Result<(), Error> { - R::from_rng(&mut self.reseeder).map(|result| { - self.bytes_until_reseed = self.threshold; - self.inner = result - }) - } - - fn is_forked(&self, global_fork_counter: usize) -> bool { - // In theory, on 32-bit platforms, it is possible for - // `global_fork_counter` to wrap around after ~4e9 forks. - // - // This check will detect a fork in the normal case where - // `fork_counter < global_fork_counter`, and also when the difference - // between both is greater than `isize::MAX` (wrapped around). - // - // It will still fail to detect a fork if there have been more than - // `isize::MAX` forks, without any reseed in between. Seems unlikely - // enough. - (self.fork_counter.wrapping_sub(global_fork_counter) as isize) < 0 - } - - #[inline(never)] - fn reseed_and_generate(&mut self, - results: &mut <Self as BlockRngCore>::Results, - global_fork_counter: usize) - { - #![allow(clippy::if_same_then_else)] // false positive - if self.is_forked(global_fork_counter) { - info!("Fork detected, reseeding RNG"); - } else { - trace!("Reseeding RNG (periodic reseed)"); - } - - let num_bytes = - results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>(); - - if let Err(e) = self.reseed() { - warn!("Reseeding RNG failed: {}", e); - let _ = e; - } - self.fork_counter = global_fork_counter; - - self.bytes_until_reseed = self.threshold - num_bytes as i64; - self.inner.generate(results); - } -} - -impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr> -where R: BlockRngCore + SeedableRng + Clone, - Rsdr: RngCore + Clone -{ - fn clone(&self) -> ReseedingCore<R, Rsdr> { - ReseedingCore { - inner: self.inner.clone(), - reseeder: self.reseeder.clone(), - threshold: self.threshold, - bytes_until_reseed: 0, // reseed clone on first use - fork_counter: self.fork_counter, - } - } -} - -impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr> -where R: BlockRngCore + SeedableRng + CryptoRng, - Rsdr: RngCore + CryptoRng {} - - -#[cfg(all(unix, not(target_os="emscripten")))] -mod fork { - use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering}; - #[allow(deprecated)] // Required for compatibility with Rust < 1.24. - use core::sync::atomic::{ATOMIC_USIZE_INIT, ATOMIC_BOOL_INIT}; - - // Fork protection - // - // We implement fork protection on Unix using `pthread_atfork`. - // When the process is forked, we increment `RESEEDING_RNG_FORK_COUNTER`. - // Every `ReseedingRng` stores the last known value of the static in - // `fork_counter`. If the cached `fork_counter` is less than - // `RESEEDING_RNG_FORK_COUNTER`, it is time to reseed this RNG. - // - // If reseeding fails, we don't deal with this by setting a delay, but just - // don't update `fork_counter`, so a reseed is attempted as soon as - // possible. - - #[allow(deprecated)] - static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; - - pub fn get_fork_counter() -> usize { - RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed) - } - - #[allow(deprecated)] - static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT; - - extern fn fork_handler() { - // Note: fetch_add is defined to wrap on overflow - // (which is what we want). - RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed); - } - - pub fn register_fork_handler() { - if !FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) { - unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) }; - FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed); - } - } -} - -#[cfg(not(all(unix, not(target_os="emscripten"))))] -mod fork { - pub fn get_fork_counter() -> usize { 0 } - pub fn register_fork_handler() {} -} - - -#[cfg(test)] -mod test { - use crate::{Rng, SeedableRng}; - use crate::rngs::std::Core; - use crate::rngs::mock::StepRng; - use super::ReseedingRng; - - #[test] - fn test_reseeding() { - let mut zero = StepRng::new(0, 0); - let rng = Core::from_rng(&mut zero).unwrap(); - let thresh = 1; // reseed every time the buffer is exhausted - let mut reseeding = ReseedingRng::new(rng, thresh, zero); - - // RNG buffer size is [u32; 64] - // Debug is only implemented up to length 32 so use two arrays - let mut buf = ([0u32; 32], [0u32; 32]); - reseeding.fill(&mut buf.0); - reseeding.fill(&mut buf.1); - let seq = buf; - for _ in 0..10 { - reseeding.fill(&mut buf.0); - reseeding.fill(&mut buf.1); - assert_eq!(buf, seq); - } - } - - #[test] - fn test_clone_reseeding() { - let mut zero = StepRng::new(0, 0); - let rng = Core::from_rng(&mut zero).unwrap(); - let mut rng1 = ReseedingRng::new(rng, 32*4, zero); - - let first: u32 = rng1.gen(); - for _ in 0..10 { let _ = rng1.gen::<u32>(); } - - let mut rng2 = rng1.clone(); - assert_eq!(first, rng2.gen::<u32>()); - } -} diff --git a/rand/src/rngs/entropy.rs b/rand/src/rngs/entropy.rs deleted file mode 100644 index 1ed59ab..0000000 --- a/rand/src/rngs/entropy.rs +++ /dev/null @@ -1,76 +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. - -//! Entropy generator, or wrapper around external generators - -#![allow(deprecated)] // whole module is deprecated - -use rand_core::{RngCore, CryptoRng, Error}; -use crate::rngs::OsRng; - -/// An interface returning random data from external source(s), provided -/// specifically for securely seeding algorithmic generators (PRNGs). -/// -/// This is deprecated. It is suggested you use [`rngs::OsRng`] instead. -/// -/// [`rngs::OsRng`]: crate::rngs::OsRng -#[derive(Debug)] -#[deprecated(since="0.7.0", note="use rngs::OsRng instead")] -pub struct EntropyRng { - source: OsRng, -} - -impl EntropyRng { - /// Create a new `EntropyRng`. - /// - /// This method will do no system calls or other initialization routines, - /// those are done on first use. This is done to make `new` infallible, - /// and `try_fill_bytes` the only place to report errors. - pub fn new() -> Self { - EntropyRng { source: OsRng } - } -} - -impl Default for EntropyRng { - fn default() -> Self { - EntropyRng::new() - } -} - -impl RngCore for EntropyRng { - fn next_u32(&mut self) -> u32 { - self.source.next_u32() - } - - fn next_u64(&mut self) -> u64 { - self.source.next_u64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.source.fill_bytes(dest) - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.source.try_fill_bytes(dest) - } -} - -impl CryptoRng for EntropyRng {} - - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_entropy() { - let mut rng = EntropyRng::new(); - let n = (rng.next_u32() ^ rng.next_u32()).count_ones(); - assert!(n >= 2); // p(failure) approx 1e-7 - } -} diff --git a/rand/src/rngs/mock.rs b/rand/src/rngs/mock.rs deleted file mode 100644 index b4081da..0000000 --- a/rand/src/rngs/mock.rs +++ /dev/null @@ -1,64 +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. - -//! Mock random number generator - -use rand_core::{RngCore, Error, impls}; - -/// A simple implementation of `RngCore` for testing purposes. -/// -/// This generates an arithmetic sequence (i.e. adds a constant each step) -/// over a `u64` number, using wrapping arithmetic. If the increment is 0 -/// the generator yields a constant. -/// -/// ``` -/// use rand::Rng; -/// use rand::rngs::mock::StepRng; -/// -/// let mut my_rng = StepRng::new(2, 1); -/// let sample: [u64; 3] = my_rng.gen(); -/// assert_eq!(sample, [2, 3, 4]); -/// ``` -#[derive(Debug, Clone)] -pub struct StepRng { - v: u64, - a: u64, -} - -impl StepRng { - /// Create a `StepRng`, yielding an arithmetic sequence starting with - /// `initial` and incremented by `increment` each time. - pub fn new(initial: u64, increment: u64) -> Self { - StepRng { v: initial, a: increment } - } -} - -impl RngCore for StepRng { - #[inline] - fn next_u32(&mut self) -> u32 { - self.next_u64() as u32 - } - - #[inline] - fn next_u64(&mut self) -> u64 { - let result = self.v; - self.v = self.v.wrapping_add(self.a); - result - } - - #[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(()) - } -} diff --git a/rand/src/rngs/mod.rs b/rand/src/rngs/mod.rs deleted file mode 100644 index abf3243..0000000 --- a/rand/src/rngs/mod.rs +++ /dev/null @@ -1,119 +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. - -//! Random number generators and adapters -//! -//! ## Background: Random number generators (RNGs) -//! -//! Computers cannot produce random numbers from nowhere. We classify -//! random number generators as follows: -//! -//! - "True" random number generators (TRNGs) use hard-to-predict data sources -//! (e.g. the high-resolution parts of event timings and sensor jitter) to -//! harvest random bit-sequences, apply algorithms to remove bias and -//! estimate available entropy, then combine these bits into a byte-sequence -//! or an entropy pool. This job is usually done by the operating system or -//! a hardware generator (HRNG). -//! - "Pseudo"-random number generators (PRNGs) use algorithms to transform a -//! seed into a sequence of pseudo-random numbers. These generators can be -//! fast and produce well-distributed unpredictable random numbers (or not). -//! They are usually deterministic: given algorithm and seed, the output -//! sequence can be reproduced. They have finite period and eventually loop; -//! with many algorithms this period is fixed and can be proven sufficiently -//! long, while others are chaotic and the period depends on the seed. -//! - "Cryptographically secure" pseudo-random number generators (CSPRNGs) -//! are the sub-set of PRNGs which are secure. Security of the generator -//! relies both on hiding the internal state and using a strong algorithm. -//! -//! ## Traits and functionality -//! -//! All RNGs implement the [`RngCore`] trait, as a consequence of which the -//! [`Rng`] extension trait is automatically implemented. Secure RNGs may -//! additionally implement the [`CryptoRng`] trait. -//! -//! All PRNGs require a seed to produce their random number sequence. The -//! [`SeedableRng`] trait provides three ways of constructing PRNGs: -//! -//! - `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 -//! -//! Use the [`rand_core`] crate when implementing your own RNGs. -//! -//! ## Our generators -//! -//! This crate provides several random number generators: -//! -//! - [`OsRng`] is an interface to the operating system's random number -//! source. Typically the operating system uses a CSPRNG with entropy -//! provided by a TRNG and some type of on-going re-seeding. -//! - [`ThreadRng`], provided by the [`thread_rng`] function, is a handle to a -//! thread-local CSPRNG with periodic seeding from [`OsRng`]. Because this -//! is local, it is typically much faster than [`OsRng`]. It should be -//! secure, though the paranoid may prefer [`OsRng`]. -//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security -//! (based on reviews, maturity and usage). The current algorithm is ChaCha20, -//! which is well established and rigorously analysed. -//! [`StdRng`] provides the algorithm used by [`ThreadRng`] but without -//! periodic reseeding. -//! - [`SmallRng`] is an **insecure** PRNG designed to be fast, simple, require -//! little memory, and have good output quality. -//! -//! The algorithms selected for [`StdRng`] and [`SmallRng`] may change in any -//! release and may be platform-dependent, therefore they should be considered -//! **not reproducible**. -//! -//! ## Additional generators -//! -//! **TRNGs**: The [`rdrand`] crate provides an interface to the RDRAND and -//! RDSEED instructions available in modern Intel and AMD CPUs. -//! The [`rand_jitter`] crate provides a user-space implementation of -//! entropy harvesting from CPU timer jitter, but is very slow and has -//! [security issues](https://github.com/rust-random/rand/issues/699). -//! -//! **PRNGs**: Several companion crates are available, providing individual or -//! families of PRNG algorithms. These provide the implementations behind -//! [`StdRng`] and [`SmallRng`] but can also be used directly, indeed *should* -//! be used directly when **reproducibility** matters. -//! Some suggestions are: [`rand_chacha`], [`rand_pcg`], [`rand_xoshiro`]. -//! A full list can be found by searching for crates with the [`rng` tag]. -//! -//! [`SmallRng`]: rngs::SmallRng -//! [`StdRng`]: rngs::StdRng -//! [`OsRng`]: rngs::OsRng -//! [`ThreadRng`]: rngs::ThreadRng -//! [`mock::StepRng`]: rngs::mock::StepRng -//! [`adapter::ReadRng`]: rngs::adapter::ReadRng -//! [`adapter::ReseedingRng`]: rngs::adapter::ReseedingRng -//! [`rdrand`]: https://crates.io/crates/rdrand -//! [`rand_jitter`]: https://crates.io/crates/rand_jitter -//! [`rand_chacha`]: https://crates.io/crates/rand_chacha -//! [`rand_pcg`]: https://crates.io/crates/rand_pcg -//! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro -//! [`rng` tag]: https://crates.io/keywords/rng - -pub mod adapter; - -#[cfg(feature="std")] mod entropy; -pub mod mock; // Public so we don't export `StepRng` directly, making it a bit - // more clear it is intended for testing. -#[cfg(feature="small_rng")] -mod small; -mod std; -#[cfg(feature="std")] pub(crate) mod thread; - -#[allow(deprecated)] -#[cfg(feature="std")] pub use self::entropy::EntropyRng; - -#[cfg(feature="small_rng")] -pub use self::small::SmallRng; -pub use self::std::StdRng; -#[cfg(feature="std")] pub use self::thread::ThreadRng; - -#[cfg(feature="getrandom")] pub use rand_core::OsRng; diff --git a/rand/src/rngs/small.rs b/rand/src/rngs/small.rs deleted file mode 100644 index 6571363..0000000 --- a/rand/src/rngs/small.rs +++ /dev/null @@ -1,115 +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. - -//! A small fast RNG - -use rand_core::{RngCore, SeedableRng, Error}; - -#[cfg(all(not(target_os = "emscripten"), target_pointer_width = "64"))] -type Rng = rand_pcg::Pcg64Mcg; -#[cfg(not(all(not(target_os = "emscripten"), target_pointer_width = "64")))] -type Rng = rand_pcg::Pcg32; - -/// A small-state, fast non-crypto PRNG -/// -/// `SmallRng` may be a good choice when a PRNG with small state, cheap -/// initialization, good statistical quality and good performance are required. -/// It is **not** a good choice when security against prediction or -/// reproducibility are important. -/// -/// This PRNG is **feature-gated**: to use, you must enable the crate feature -/// `small_rng`. -/// -/// 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_pcg] or [rand_chacha]. -/// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html). -/// -/// 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 [`StdRng`]. -/// The current algorithm is [`Pcg64Mcg`](rand_pcg::Pcg64Mcg) on 64-bit -/// platforms and [`Pcg32`](rand_pcg::Pcg32) on 32-bit platforms. Both are -/// implemented by the [rand_pcg] 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 std::iter; -/// 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<SmallRng> = iter::repeat(()) -/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) -/// .take(10) -/// .collect(); -/// ``` -/// -/// [`StdRng`]: crate::rngs::StdRng -/// [`thread_rng`]: crate::thread_rng -/// [rand_chacha]: https://crates.io/crates/rand_chacha -/// [rand_pcg]: https://crates.io/crates/rand_pcg -#[derive(Clone, Debug)] -pub struct SmallRng(Rng); - -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() - } - - #[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) - } -} - -impl SeedableRng for SmallRng { - type Seed = <Rng as SeedableRng>::Seed; - - #[inline(always)] - fn from_seed(seed: Self::Seed) -> Self { - SmallRng(Rng::from_seed(seed)) - } - - #[inline(always)] - fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { - Rng::from_rng(rng).map(SmallRng) - } -} diff --git a/rand/src/rngs/std.rs b/rand/src/rngs/std.rs deleted file mode 100644 index 22e08ae..0000000 --- a/rand/src/rngs/std.rs +++ /dev/null @@ -1,100 +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. - -//! The standard RNG - -use crate::{RngCore, CryptoRng, Error, SeedableRng}; - -#[cfg(target_os = "emscripten")] pub(crate) use rand_hc::Hc128Core as Core; -#[cfg(not(target_os = "emscripten"))] pub(crate) use rand_chacha::ChaCha20Core as Core; -#[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng; -#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha20Rng as Rng; - -/// 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 is the ChaCha block cipher with either 20 or 12 -/// rounds (see the `stdrng_*` feature flags, documented in the README). -/// This may change as new evidence of cipher security and performance -/// becomes available. -/// -/// The algorithm is deterministic but should not be considered reproducible -/// due to dependence on configuration and possible replacement in future -/// library versions. For a secure reproducible generator, we recommend use of -/// the [rand_chacha] crate directly. -/// -/// [rand_chacha]: https://crates.io/crates/rand_chacha -#[derive(Clone, Debug)] -pub struct StdRng(Rng); - -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() - } - - #[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) - } -} - -impl SeedableRng for StdRng { - type Seed = <Rng as SeedableRng>::Seed; - - #[inline(always)] - 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 {} - - -#[cfg(test)] -mod test { - use crate::{RngCore, SeedableRng}; - use crate::rngs::StdRng; - - #[test] - fn test_stdrng_construction() { - // Test value-stability of StdRng. This is expected to break any time - // the algorithm is changed. - 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]; - - #[cfg(any(feature="stdrng_strong", not(feature="stdrng_fast")))] - let target = [3950704604716924505, 5573172343717151650]; - #[cfg(all(not(feature="stdrng_strong"), feature="stdrng_fast"))] - let target = [10719222850664546238, 14064965282130556830]; - - let mut rng0 = StdRng::from_seed(seed); - let x0 = rng0.next_u64(); - - let mut rng1 = StdRng::from_rng(rng0).unwrap(); - let x1 = rng1.next_u64(); - - assert_eq!([x0, x1], target); - } -} diff --git a/rand/src/rngs/thread.rs b/rand/src/rngs/thread.rs deleted file mode 100644 index 2006f41..0000000 --- a/rand/src/rngs/thread.rs +++ /dev/null @@ -1,124 +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. - -//! Thread-local random number generator - -use std::cell::UnsafeCell; -use std::ptr::NonNull; - -use crate::{RngCore, CryptoRng, SeedableRng, Error}; -use crate::rngs::adapter::ReseedingRng; -use crate::rngs::OsRng; -use super::std::Core; - -// Rationale for using `UnsafeCell` in `ThreadRng`: -// -// Previously we used a `RefCell`, with an overhead of ~15%. There will only -// ever be one mutable reference to the interior of the `UnsafeCell`, because -// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a -// single thread (which is the definition of `ThreadRng`), there will only ever -// be one of these methods active at a time. -// -// A possible scenario where there could be multiple mutable references is if -// `ThreadRng` is used inside `next_u32` and co. But the implementation is -// completely under our control. We just have to ensure none of them use -// `ThreadRng` internally, which is nonsensical anyway. We should also never run -// `ThreadRng` in destructors of its implementation, which is also nonsensical. - - -// Number of generated bytes after which to reseed `ThreadRng`. -// According to benchmarks, reseeding has a noticable impact with thresholds -// of 32 kB and less. We choose 64 kB to avoid significant overhead. -const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64; - -/// The type returned by [`thread_rng`], essentially just a reference to the -/// PRNG in thread-local memory. -/// -/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance. -/// As hinted by the name, the generator is thread-local. `ThreadRng` is a -/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`. -/// -/// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed -/// the PRNG from fresh entropy every 64 kiB of random data. -/// [`OsRng`] is used to provide seed data. -/// -/// Note that the reseeding is done as an extra precaution against side-channel -/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially). -/// The PRNG algorithms used are assumed to be secure. -/// -/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng -/// [`StdRng`]: crate::rngs::StdRng -#[derive(Copy, Clone, Debug)] -pub struct ThreadRng { - // inner raw pointer implies type is neither Send nor Sync - rng: NonNull<ReseedingRng<Core, OsRng>>, -} - -thread_local!( - static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = { - let r = Core::from_rng(OsRng).unwrap_or_else(|err| - panic!("could not initialize thread_rng: {}", err)); - let rng = ReseedingRng::new(r, - THREAD_RNG_RESEED_THRESHOLD, - OsRng); - UnsafeCell::new(rng) - } -); - -/// 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::<i32>()`, or cached locally, e.g. -/// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making -/// `ThreadRng::default()` equivalent. -/// -/// For more information see [`ThreadRng`]. -pub fn thread_rng() -> ThreadRng { - let raw = THREAD_RNG_KEY.with(|t| t.get()); - let nn = NonNull::new(raw).unwrap(); - ThreadRng { rng: nn } -} - -impl Default for ThreadRng { - fn default() -> ThreadRng { - crate::prelude::thread_rng() - } -} - -impl RngCore for ThreadRng { - #[inline(always)] - fn next_u32(&mut self) -> u32 { - unsafe { self.rng.as_mut().next_u32() } - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - unsafe { self.rng.as_mut().next_u64() } - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - unsafe { self.rng.as_mut().fill_bytes(dest) } - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - unsafe { self.rng.as_mut().try_fill_bytes(dest) } - } -} - -impl CryptoRng for ThreadRng {} - - -#[cfg(test)] -mod test { - #[test] - fn test_thread_rng() { - use crate::Rng; - let mut r = crate::thread_rng(); - r.gen::<i32>(); - assert_eq!(r.gen_range(0, 1), 0); - } -} |