| // Copyright 2017 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 <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. |
| |
| //! Pseudo-random number generators. |
| //! |
| //! Pseudo-random number generators are algorithms to produce apparently random |
| //! numbers deterministically, and usually fairly quickly. See the documentation |
| //! of the [`rngs` module] for some introduction to PRNGs. |
| //! |
| //! As mentioned there, PRNGs fall in two broad categories: |
| //! |
| //! - [basic PRNGs], primarily designed for simulations |
| //! - [CSPRNGs], primarily designed for cryptography |
| //! |
| //! In simple terms, the basic PRNGs are often predictable; CSPRNGs should not |
| //! be predictable *when used correctly*. |
| //! |
| //! Contents of this documentation: |
| //! |
| //! 1. [The generators](#the-generators) |
| //! 1. [Performance and size](#performance) |
| //! 1. [Quality and cycle length](#quality) |
| //! 1. [Security](#security) |
| //! 1. [Extra features](#extra-features) |
| //! 1. [Further reading](#further-reading) |
| //! |
| //! |
| //! # The generators |
| //! |
| //! ## Basic pseudo-random number generators (PRNGs) |
| //! |
| //! The goal of regular, non-cryptographic PRNGs is usually to find a good |
| //! balance between simplicity, quality, memory usage and performance. These |
| //! algorithms are very important to Monte Carlo simulations, and also suitable |
| //! for several other problems such as randomized algorithms and games (except |
| //! where there is a risk of players predicting the next output value from |
| //! previous values, in which case a CSPRNG should be used). |
| //! |
| //! Currently Rand provides only one PRNG, and not a very good one at that: |
| //! |
| //! | name | full name | performance | memory | quality | period | features | |
| //! |------|-----------|-------------|--------|---------|--------|----------| |
| //! | [`XorShiftRng`] | Xorshift 32/128 | ★★★☆☆ | 16 bytes | ★☆☆☆☆ | `u32` * 2<sup>128</sup> - 1 | — | |
| //! |
| // Quality stars [not rendered in documentation]: |
| // 5. reserved for crypto-level (e.g. ChaCha8, ISAAC) |
| // 4. good performance on TestU01 and PractRand, good theory |
| // (e.g. PCG, truncated Xorshift*) |
| // 3. good performance on TestU01 and PractRand, but "falling through the |
| // cracks" or insufficient theory (e.g. SFC, Xoshiro) |
| // 2. imperfect performance on tests or other limiting properties, but not |
| // terrible (e.g. Xoroshiro128+) |
| // 1. clear deficiencies in test results, cycle length, theory, or other |
| // properties (e.g. Xorshift) |
| // |
| // Performance stars [not rendered in documentation]: |
| // Meant to give an indication of relative performance. Roughly follows a log |
| // scale, based on the performance of `next_u64` on a current i5/i7: |
| // - 5. 8000 MB/s+ |
| // - 4. 4000 MB/s+ |
| // - 3. 2000 MB/s+ |
| // - 2. 1000 MB/s+ |
| // - 1. < 1000 MB/s |
| // |
| //! ## Cryptographically secure pseudo-random number generators (CSPRNGs) |
| //! |
| //! CSPRNGs have much higher requirements than basic PRNGs. The primary |
| //! consideration is security. Performance and simplicity are also important, |
| //! but in general CSPRNGs are more complex and slower than regular PRNGs. |
| //! Quality is no longer a concern, as it is a requirement for a |
| //! CSPRNG that the output is basically indistinguishable from true randomness |
| //! since any bias or correlation makes the output more predictable. |
| //! |
| //! There is a close relationship between CSPRNGs and cryptographic ciphers. |
| //! Any block cipher can be turned into a CSPRNG by encrypting a counter. Stream |
| //! ciphers are basically a CSPRNG and a combining operation, usually XOR. This |
| //! means that we can easily use any stream cipher as a CSPRNG. |
| //! |
| //! Rand currently provides two trustworthy CSPRNGs and two CSPRNG-like PRNGs: |
| //! |
| //! | name | full name | performance | initialization | memory | predictability | forward secrecy | |
| //! |------|-----------|--------------|--------------|----------|----------------|-------------------------| |
| //! | [`ChaChaRng`] | ChaCha20 | ★☆☆☆☆ | fast | 136 bytes | secure | no | |
| //! | [`Hc128Rng`] | HC-128 | ★★☆☆☆ | slow | 4176 bytes | secure | no | |
| //! | [`IsaacRng`] | ISAAC | ★★☆☆☆ | slow | 2072 bytes | unknown | unknown | |
| //! | [`Isaac64Rng`] | ISAAC-64 | ★★☆☆☆ | slow | 4136 bytes| unknown | unknown | |
| //! |
| //! It should be noted that the ISAAC generators are only included for |
| //! historical reasons, they have been with the Rust language since the very |
| //! beginning. They have good quality output and no attacks are known, but have |
| //! received little attention from cryptography experts. |
| //! |
| //! |
| //! # Performance |
| //! |
| //! First it has to be said most PRNGs are very fast, and will rarely be a |
| //! performance bottleneck. |
| //! |
| //! Performance of basic PRNGs is a bit of a subtle thing. It depends a lot on |
| //! the CPU architecture (32 vs. 64 bits), inlining, and also on the number of |
| //! available registers. This often causes the performance to be affected by |
| //! surrounding code due to inlining and other usage of registers. |
| //! |
| //! When choosing a PRNG for performance it is important to benchmark your own |
| //! application due to interactions between PRNGs and surrounding code and |
| //! dependence on the CPU architecture as well as the impact of the size of |
| //! data requested. Because of all this, we do not include performance numbers |
| //! here but merely a qualitative rating. |
| //! |
| //! CSPRNGs are a little different in that they typically generate a block of |
| //! output in a cache, and pull outputs from the cache. This allows them to have |
| //! good amortised performance, and reduces or completely removes the influence |
| //! of surrounding code on the CSPRNG performance. |
| //! |
| //! ### Worst-case performance |
| //! Because CSPRNGs usually produce a block of values into a cache, they have |
| //! poor worst case performance (in contrast to basic PRNGs, where the |
| //! performance is usually quite regular). |
| //! |
| //! ## State size |
| //! |
| //! Simple PRNGs often use very little memory, commonly only a few words, where |
| //! a *word* is usually either `u32` or `u64`. This is not true for all |
| //! non-cryptographic PRNGs however, for example the historically popular |
| //! Mersenne Twister MT19937 algorithm requires 2.5 kB of state. |
| //! |
| //! CSPRNGs typically require more memory; since the seed size is recommended |
| //! to be at least 192 bits and some more may be required for the algorithm, |
| //! 256 bits would be approximately the minimum secure size. In practice, |
| //! CSPRNGs tend to use quite a bit more, [`ChaChaRng`] is relatively small with |
| //! 136 bytes of state. |
| //! |
| //! ## Initialization time |
| //! |
| //! The time required to initialize new generators varies significantly. Many |
| //! simple PRNGs and even some cryptographic ones (including [`ChaChaRng`]) |
| //! only need to copy the seed value and some constants into their state, and |
| //! thus can be constructed very quickly. In contrast, CSPRNGs with large state |
| //! require an expensive key-expansion. |
| //! |
| //! # Quality |
| //! |
| //! Many basic PRNGs are not much more than a couple of bitwise and arithmetic |
| //! operations. Their simplicity gives good performance, but also means there |
| //! are small regularities hidden in the generated random number stream. |
| //! |
| //! How much do those hidden regularities matter? That is hard to say, and |
| //! depends on how the RNG gets used. If there happen to be correlations between |
| //! the random numbers and the algorithm they are used in, the results can be |
| //! wrong or misleading. |
| //! |
| //! A random number generator can be considered good if it gives the correct |
| //! results in as many applications as possible. The quality of PRNG |
| //! algorithms can be evaluated to some extend analytically, to determine the |
| //! cycle length and to rule out some correlations. Then there are empirical |
| //! test suites designed to test how well a PRNG performs on a wide range of |
| //! possible uses, the latest and most complete of which are [TestU01] and |
| //! [PractRand]. |
| //! |
| //! CSPRNGs tend to be more complex, and have an explicit requirement to be |
| //! unpredictable. This implies there must be no obvious correlations between |
| //! output values. |
| //! |
| //! ### Quality stars: |
| //! PRNGs with 3 stars or more should be good enough for any purpose. |
| //! 1 or 2 stars may be good enough for typical apps and games, but do not work |
| //! well with all algorithms. |
| //! |
| //! ## Period |
| //! |
| //! The *period* or *cycle length* of a PRNG is the number of values that can be |
| //! generated after which it starts repeating the same random number stream. |
| //! Many PRNGs have a fixed-size period, but for some only an expected average |
| //! cycle length can be given, where the exact length depends on the seed. |
| //! |
| //! On today's hardware, even a fast RNG with a cycle length of *only* |
| //! 2<sup>64</sup> can be used for centuries before cycling. Yet we recommend a |
| //! period of 2<sup>128</sup> or more, which most modern PRNGs satisfy. |
| //! Alternatively a PRNG with shorter period but support for multiple streams |
| //! may be chosen. There are two reasons for this, as follows. |
| //! |
| //! If we see the entire period of an RNG as one long random number stream, |
| //! every independently seeded RNG returns a slice of that stream. When multiple |
| //! RNG are seeded randomly, there is an increasingly large chance to end up |
| //! with a partially overlapping slice of the stream. |
| //! |
| //! If the period of the RNG is 2<sup>128</sup>, and an application consumes |
| //! 2<sup>48</sup> values, it then takes about 2<sup>32</sup> random |
| //! initializations to have a chance of 1 in a million to repeat part of an |
| //! already used stream. This seems good enough for common usage of |
| //! non-cryptographic generators, hence the recommendation of at least |
| //! 2<sup>128</sup>. As an estimate, the chance of any overlap in a period of |
| //! size `p` with `n` independent seeds and `u` values used per seed is |
| //! approximately `1 - e^(-u * n^2 / (2 * p))`. |
| //! |
| //! Further, it is not recommended to use the full period of an RNG. Many |
| //! PRNGs have a property called *k-dimensional equidistribution*, meaning that |
| //! for values of some size (potentially larger than the output size), all |
| //! possible values are produced the same number of times over the generator's |
| //! period. This is not a property of true randomness. This is known as the |
| //! generalized birthday problem, see the [PCG paper] for a good explanation. |
| //! This results in a noticable bias on output after generating more values |
| //! than the square root of the period (after 2<sup>64</sup> values for a |
| //! period of 2<sup>128</sup>). |
| //! |
| //! |
| //! # Security |
| //! |
| //! ## Predictability |
| //! |
| //! From the context of any PRNG, one can ask the question *given some previous |
| //! output from the PRNG, is it possible to predict the next output value?* |
| //! This is an important property in any situation where there might be an |
| //! adversary. |
| //! |
| //! Regular PRNGs tend to be predictable, although with varying difficulty. In |
| //! some cases prediction is trivial, for example plain Xorshift outputs part of |
| //! its state without mutation, and prediction is as simple as seeding a new |
| //! Xorshift generator from four `u32` outputs. Other generators, like |
| //! [PCG](http://www.pcg-random.org/predictability.html) and truncated Xorshift* |
| //! are harder to predict, but not outside the realm of common mathematics and a |
| //! desktop PC. |
| //! |
| //! The basic security that CSPRNGs must provide is the infeasibility to predict |
| //! output. This requirement is formalized as the [next-bit test]; this is |
| //! roughly stated as: given the first *k* bits of a random sequence, the |
| //! sequence satisfies the next-bit test if there is no algorithm able to |
| //! predict the next bit using reasonable computing power. |
| //! |
| //! A further security that *some* CSPRNGs provide is forward secrecy: |
| //! in the event that the CSPRNGs state is revealed at some point, it must be |
| //! infeasible to reconstruct previous states or output. Note that many CSPRNGs |
| //! *do not* have forward secrecy in their usual formulations. |
| //! |
| //! As an outsider it is hard to get a good idea about the security of an |
| //! algorithm. People in the field of cryptography spend a lot of effort |
| //! analyzing existing designs, and what was once considered good may now turn |
| //! out to be weaker. Generally it is best to use algorithms well-analyzed by |
| //! experts, such as those recommended by NIST or ECRYPT. |
| //! |
| //! ## State and seeding |
| //! |
| //! It is worth noting that a CSPRNG's security relies absolutely on being |
| //! seeded with a secure random key. Should the key be known or guessable, all |
| //! output of the CSPRNG is easy to guess. This implies that the seed should |
| //! come from a trusted source; usually either the OS or another CSPRNG. Our |
| //! seeding helper trait, [`FromEntropy`], and the source it uses |
| //! ([`EntropyRng`]), should be secure. Additionally, [`ThreadRng`] is a CSPRNG, |
| //! thus it is acceptable to seed from this (although for security applications |
| //! fresh/external entropy should be preferred). |
| //! |
| //! Further, it should be obvious that the internal state of a CSPRNG must be |
| //! kept secret. With that in mind, our implementations do not provide direct |
| //! access to most of their internal state, and `Debug` implementations do not |
| //! print any internal state. This does not fully protect CSPRNG state; code |
| //! within the same process may read this memory (and we allow cloning and |
| //! serialisation of CSPRNGs for convenience). Further, a running process may be |
| //! forked by the operating system, which may leave both processes with a copy |
| //! of the same generator. |
| //! |
| //! ## Not a crypto library |
| //! |
| //! It should be emphasised that this is not a cryptography library; although |
| //! Rand does take some measures to provide secure random numbers, it does not |
| //! necessarily take all recommended measures. Further, cryptographic processes |
| //! such as encryption and authentication are complex and must be implemented |
| //! very carefully to avoid flaws and resist known attacks. It is therefore |
| //! recommended to use specialized libraries where possible, for example |
| //! [openssl], [ring] and the [RustCrypto libraries]. |
| //! |
| //! |
| //! # Extra features |
| //! |
| //! Some PRNGs may provide extra features, like: |
| //! |
| //! - Support for multiple streams, which can help with parallel tasks. |
| //! - The ability to jump or seek around in the random number stream; |
| //! with large periood this can be used as an alternative to streams. |
| //! |
| //! |
| //! # Further reading |
| //! |
| //! There is quite a lot that can be said about PRNGs. The [PCG paper] is a |
| //! very approachable explaining more concepts. |
| //! |
| //! A good paper about RNG quality is |
| //! ["Good random number generators are (not so) easy to find"]( |
| //! http://random.mat.sbg.ac.at/results/peter/A19final.pdf) by P. Hellekalek. |
| //! |
| //! |
| //! [`rngs` module]: ../rngs/index.html |
| //! [basic PRNGs]: #basic-pseudo-random-number-generators-prngs |
| //! [CSPRNGs]: #cryptographically-secure-pseudo-random-number-generators-csprngs |
| //! [`XorShiftRng`]: struct.XorShiftRng.html |
| //! [`ChaChaRng`]: chacha/struct.ChaChaRng.html |
| //! [`Hc128Rng`]: hc128/struct.Hc128Rng.html |
| //! [`IsaacRng`]: isaac/struct.IsaacRng.html |
| //! [`Isaac64Rng`]: isaac64/struct.Isaac64Rng.html |
| //! [`ThreadRng`]: ../rngs/struct.ThreadRng.html |
| //! [`FromEntropy`]: ../trait.FromEntropy.html |
| //! [`EntropyRng`]: ../rngs/struct.EntropyRng.html |
| //! [TestU01]: http://simul.iro.umontreal.ca/testu01/tu01.html |
| //! [PractRand]: http://pracrand.sourceforge.net/ |
| //! [PCG paper]: http://www.pcg-random.org/pdf/hmc-cs-2014-0905.pdf |
| //! [openssl]: https://crates.io/crates/openssl |
| //! [ring]: https://crates.io/crates/ring |
| //! [RustCrypto libraries]: https://github.com/RustCrypto |
| //! [next-bit test]: https://en.wikipedia.org/wiki/Next-bit_test |
| |
| |
| pub mod chacha; |
| pub mod hc128; |
| pub mod isaac; |
| pub mod isaac64; |
| mod xorshift; |
| |
| mod isaac_array; |
| |
| pub use self::chacha::ChaChaRng; |
| pub use self::hc128::Hc128Rng; |
| pub use self::isaac::IsaacRng; |
| pub use self::isaac64::Isaac64Rng; |
| pub use self::xorshift::XorShiftRng; |