diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 483bc4bbf73..93da90208d4 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -251,7 +251,7 @@ pub trait BlockRngCore { /// predict the next bit with probability significantly greater than 50%. /// /// Some generators may satisfy an additional property, however this is not -/// required: if the CSPRNG's state is revealed, it should not be +/// required by this trait: if the CSPRNG's state is revealed, it should not be /// computationally-feasible to reconstruct output prior to this. Some other /// generators allow backwards-computation and are consided *reversible*. /// diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 6afbf923709..ae259843ac4 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -10,10 +10,18 @@ //! Sampling from random distributions. //! -//! A distribution may have internal state describing the distribution of -//! generated values; for example `Range` needs to know its upper and lower -//! bounds. Distributions use the `Distribution` trait to yield values: call -//! `distr.sample(&mut rng)` to get a random variable. +//! Distributions are stateless (i.e. immutable) objects controlling the +//! production of values of some type `T` from a presumed uniform randomness +//! source. These objects may have internal parameters set at contruction time +//! (e.g. [`Range`], which has configurable bounds) or may have no internal +//! parameters (e.g. [`Standard`]). +//! +//! All distributions support the [`Distribution`] trait, and support usage +//! via `distr.sample(&mut rng)` as well as via `rng.sample(distr)`. +//! +//! [`Distribution`]: trait.Distribution.html +//! [`Range`]: range/struct.Range.html +//! [`Standard`]: struct.Standard.html use Rng; @@ -129,6 +137,10 @@ mod impls { } /// Types (distributions) that can be used to create a random instance of `T`. +/// +/// All implementations are expected to be immutable; this has the significant +/// advantage of not needing to consider thread safety, and for most +/// distributions efficient state-less sampling algorithms are available. pub trait Distribution { /// Generate a random value of `T`, using `rng` as the source of randomness. fn sample(&self, rng: &mut R) -> T; @@ -260,9 +272,9 @@ impl<'a, T, D: Distribution> Distribution for &'a D { /// /// - The chance to generate a specific value, like exactly 0.0, is *tiny*. No /// (or almost no) sensible code relies on an exact floating-point value to be -/// generated with a very small chance (1 in ~8 million (2^23) for `f32`, and -/// 1 in 2^52 for `f64`). What is relied on is having a uniform distribution -/// and a mean of `0.5`. +/// generated with a very small chance (1 in 223 (approx. 8 +/// million) for `f32`, and 1 in 252 for `f64`). What is relied on +/// is having a uniform distribution and a mean of `0.5`. /// - Several common algorithms rely on never seeing the value `0.0` generated, /// i.e. they rely on an open interval. For example when the logarithm of the /// value is taken, or used as a devisor. diff --git a/src/entropy_rng.rs b/src/entropy_rng.rs index bcf1c6608b0..6b31fc641a2 100644 --- a/src/entropy_rng.rs +++ b/src/entropy_rng.rs @@ -14,8 +14,8 @@ use rand_core::{RngCore, CryptoRng, Error, impls}; use os::OsRng; use jitter::JitterRng; -/// A generator provided specifically for securely seeding algorithmic -/// generators (PRNGs). +/// An interface returning random data from external source(s), provided +/// specifically for securely seeding algorithmic generators (PRNGs). /// /// Where possible, `EntropyRng` retrieves random data from the operating /// system's interface for random numbers ([`OsRng`]); if that fails it will @@ -27,8 +27,9 @@ use jitter::JitterRng; /// /// This is either a little slow ([`OsRng`] requires a system call) or extremely /// slow ([`JitterRng`] must use significant CPU time to generate sufficient -/// jitter). It is recommended to only use `EntropyRng` to seed a PRNG (as in -/// [`thread_rng`]) or to generate a small key. +/// jitter); for better performance it is common to seed a local PRNG from +/// external entropy then primarily use the local PRNG ([`thread_rng`] is +/// provided as a convenient, local, automatically-seeded CSPRNG). /// /// [`OsRng`]: os/struct.OsRng.html /// [`JitterRng`]: jitter/struct.JitterRng.html diff --git a/src/lib.rs b/src/lib.rs index 2bccf0d4ab1..a572e8670c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,7 @@ //! use [`SeedableRng::from_seed`] or a constructor specific to the generator //! (e.g. [`IsaacRng::new_from_u64`]). //! -//! # Applying / converting random data +//! ## Applying / converting random data //! //! The [`RngCore`] trait allows generators to implement a common interface for //! retrieving random data, but how should you use this? Typically users should @@ -94,56 +94,43 @@ //! //! The [`seq`] module has a few tools applicable to sliceable or iterable data. //! -//! # Cryptographic security +//! ## Cryptographic security +//! +//! First, lets recap some terminology: +//! +//! - **PRNG:** *Pseudo-Random-Number-Generator* is another name for an +//! *algorithmic generator* +//! - **CSPRNG:** a *Cryptographically Secure* PRNG //! //! Security analysis requires a threat model and expert review; we can provide -//! neither, but can provide some guidance. We assume that the goal is to -//! obtain secret random data and that some source of secrets ("entropy") is -//! available; that is, [`EntropyRng`] is functional. -//! -//! Potential threat: is the entropy source secure? The primary entropy source -//! is [`OsRng`] which is simply a wrapper around the platform's native "secure -//! entropy source"; usually this is available (outside of embedded platforms) -//! and usually you can trust this (some caveats may apply; see [`OsRng`] doc). -//! The fallback source used by [`EntropyRng`] is [`JitterRng`] which runs extensive -//! tests on the quality of the CPU timer and is conservative in its estimates -//! of the entropy harvested from each time sample; this makes it slow but very -//! strong. Using [`EntropyRng`] directly should therefore be secure; the main -//! reason not to is performance, which is why many applications use local -//! algorithmic generators. -//! -//! Potential threat: are algorithmic generators predictable? Certainly some -//! are; algorithmic generators fall broadly into two categories: those using a -//! small amount of state (e.g. one to four 32- or 64-bit words) designed for -//! non-security applications and those designed to be secure, typically with -//! much larger state space and complex initialisation. The former should not be -//! trusted to be secure, the latter may or may not have known weaknesses or -//! may even have been proven secure under a specified adversarial model. We -//! provide some notes on the security of the cryptographic algorithmic -//! generators provided by this crate, [`Hc128Rng`] and [`ChaChaRng`]. Note that -//! previously [`IsaacRng`] and [`Isaac64Rng`] were used as "reasonably strong -//! generators"; these have no known weaknesses but also have no proofs of -//! security, thus are not recommended for cryptographic uses. -//! -//! Potential threat: could the internal state of a cryptographic generator be -//! leaked? This falls under the topic of "side channel attacks", and multiple -//! variants are possible: the state of the generators being accidentally -//! printed in log files or some other application output, the process's memory -//! being copied somehow, the process being forked and both sub-processes -//! outputting the same random sequence but such that one of those can be read; -//! likely some other side-channel attacks are possible in some circumstances. -//! It is typically impossible to prove immunity to all side-channel attacks, -//! however some mitigation of known threats is usually possible, for example -//! all generators implemented in this crate have a custom `Debug` -//! implementation omitting all internal state, and [`ReseedingRng`] allows -//! periodic reseeding such that a long-running process with leaked generator -//! state should eventually recover to an unknown state. In the future we plan -//! to add further mitigations; see issue #314. +//! neither, but we can provide a few hints. We assume that the goal is to +//! produce secret apparently-random data. Therefore, we need: //! -//! We provide the [`CryptoRng`] marker trait as an indication of which random -//! generators/sources may be used for cryptographic applications; this should -//! be considered advisory only does not imply any protection against -//! side-channel attacks. +//! - A good source of entropy. A known algorithm given known input data is +//! trivial to predict, and likewise if there's a non-negligable chance that +//! the input to a PRNG is guessable then there's a chance its output is too. +//! We recommend seeding CSPRNGs with [`EntropyRng`] or [`OsRng`] which +//! provide fresh "random" values from an external source. +//! One can also seed from another CSPRNG, e.g. `thread_rng`, which is faster, +//! but adds another component which must be trusted. +//! - A strong algorithmic generator. It is possible to use a good entropy +//! source like `OsRng` directly, and in some cases this is the best option, +//! but for better performance (or if requiring reproducible values generated +//! from a fixed seed) it is common to use a local CSPRNG. The basic security +//! that CSPRNGs must provide is making it infeasible to predict future output +//! given a sample of past output. A further security that *some* CSPRNGs +//! provide is *forward secrecy*; this ensures that in the event that the +//! algorithm's state is revealed, it is infeasible to reconstruct past +//! output. See the [`CryptoRng`] trait and notes on individual algorithms. +//! - To be careful not to leak secrets like keys and CSPRNG's internal state +//! and robust against "side channel attacks". This goes well beyond the scope +//! of random number generation, but this crate takes some precautions: +//! - to avoid printing CSPRNG state in log files, implementations have a +//! custom `Debug` implementation which omits all internal state +//! - `thread_rng` uses [`ReseedingRng`] to periodically refresh its state +//! - in the future we plan to add some protection against fork attacks +//! (where the process is forked and each clone generates the same "random" +//! numbers); this is not yet implemented (see issues #314, #370) //! //! # Examples //! @@ -489,9 +476,9 @@ pub trait Rng: RngCore { /// # Accuracy note /// /// `gen_bool` uses 32 bits of the RNG, so if you use it to generate close - /// to or more than 2^32 results, a tiny bias may become noticable. + /// to or more than `2^32` results, a tiny bias may become noticable. /// A notable consequence of the method used here is that the worst case is - /// `rng.gen_bool(0.0)`: it has a chance of 1 in 2^32 of being true, while + /// `rng.gen_bool(0.0)`: it has a chance of 1 in `2^32` of being true, while /// it should always be false. But using `gen_bool` to consume *many* values /// from an RNG just to consistently generate `false` does not match with /// the intent of this method. diff --git a/src/prng/isaac.rs b/src/prng/isaac.rs index 5701650890b..ce5f16b828c 100644 --- a/src/prng/isaac.rs +++ b/src/prng/isaac.rs @@ -162,11 +162,11 @@ impl BlockRngCore for IsaacCore { type Item = u32; type Results = IsaacArray; - /// Refills the output buffer (`results`) - /// See also the pseudocode desciption of the algorithm at the top of this - /// file. + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`Isaac64Rng`] documentation. /// /// Optimisations used (similar to the reference implementation): + /// /// - The loop is unrolled 4 times, once for every constant of mix(). /// - The contents of the main loop are moved to a function `rngstep`, to /// reduce code duplication. @@ -181,6 +181,8 @@ impl BlockRngCore for IsaacCore { /// from `results` in reverse. We read them in the normal direction, to /// make `fill_bytes` a memcopy. To maintain compatibility we fill in /// reverse. + /// + /// [`IsaacRng`]: struct.IsaacRng.html fn generate(&mut self, results: &mut IsaacArray) { self.c += w(1); // abbreviations diff --git a/src/prng/isaac64.rs b/src/prng/isaac64.rs index 05468fc2d84..0f61014a278 100644 --- a/src/prng/isaac64.rs +++ b/src/prng/isaac64.rs @@ -152,11 +152,11 @@ impl BlockRngCore for Isaac64Core { type Item = u64; type Results = IsaacArray; - /// Refills the output buffer (`results`) - /// See also the pseudocode desciption of the algorithm at the top of this - /// file. + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`Isaac64Rng`] documentation. /// /// Optimisations used (similar to the reference implementation): + /// /// - The loop is unrolled 4 times, once for every constant of mix(). /// - The contents of the main loop are moved to a function `rngstep`, to /// reduce code duplication. @@ -171,6 +171,8 @@ impl BlockRngCore for Isaac64Core { /// from `results` in reverse. We read them in the normal direction, to /// make `fill_bytes` a memcopy. To maintain compatibility we fill in /// reverse. + /// + /// [`Isaac64Rng`]: struct.Isaac64Rng.html fn generate(&mut self, results: &mut IsaacArray) { self.c += w(1); // abbreviations