README: rand is not a crypto library (#1514)
Closes #1358 by documenting what Rand is not. Co-authored-by: Dan <dan.middleton@intel.com>
This commit is contained in:
parent
0c36c6ca59
commit
24b9cc38ea
40
README.md
40
README.md
@ -6,20 +6,20 @@
|
||||
[](https://rust-random.github.io/rand/rand)
|
||||
[](https://docs.rs/rand)
|
||||
|
||||
Rand is a Rust library supporting random generators:
|
||||
Rand is a set of crates supporting (pseudo-)random generators:
|
||||
|
||||
- A standard RNG trait: [`rand_core::RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html)
|
||||
- Fast implementations of the best-in-class [cryptographic](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and
|
||||
[non-cryptographic](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators: [`rand::rngs`](https://docs.rs/rand/latest/rand/rngs/index.html), and more RNGs: [`rand_chacha`](https://docs.rs/rand_chacha), [`rand_xoshiro`](https://docs.rs/rand_xoshiro/), [`rand_pcg`](https://docs.rs/rand_pcg/), [rngs repo](https://github.com/rust-random/rngs/)
|
||||
- [`rand::rng`](https://docs.rs/rand/latest/rand/fn.rng.html) is an asymtotically-fast, reasonably secure generator available on all `std` targets
|
||||
- Secure seeding via the [`getrandom` crate](https://crates.io/crates/getrandom)
|
||||
- Built over a standard RNG trait: [`rand_core::RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html)
|
||||
- With fast implementations of both [strong](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and
|
||||
[small](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators: [`rand::rngs`](https://docs.rs/rand/latest/rand/rngs/index.html), and more RNGs: [`rand_chacha`](https://docs.rs/rand_chacha), [`rand_xoshiro`](https://docs.rs/rand_xoshiro/), [`rand_pcg`](https://docs.rs/rand_pcg/), [rngs repo](https://github.com/rust-random/rngs/)
|
||||
- [`rand::rng`](https://docs.rs/rand/latest/rand/fn.rng.html) is an asymptotically-fast, automatically-seeded and reasonably strong generator available on all `std` targets
|
||||
- Direct support for seeding generators from the [`getrandom` crate](https://crates.io/crates/getrandom)
|
||||
|
||||
Supporting random value generation and random processes:
|
||||
With broad support for random value generation and random processes:
|
||||
|
||||
- [`Standard`](https://docs.rs/rand/latest/rand/distributions/struct.Standard.html) random value generation
|
||||
- Ranged [`Uniform`](https://docs.rs/rand/latest/rand/distributions/struct.Uniform.html) number generation for many types
|
||||
- A flexible [`distributions`](https://docs.rs/rand/*/rand/distr/index.html) module
|
||||
- Samplers for a large number of random number distributions via our own
|
||||
- [`Standard`](https://docs.rs/rand/latest/rand/distributions/struct.Standard.html) random value sampling,
|
||||
[`Uniform`](https://docs.rs/rand/latest/rand/distributions/struct.Uniform.html)-ranged value sampling
|
||||
and [more](https://docs.rs/rand/latest/rand/distr/index.html)
|
||||
- Samplers for a large number of non-uniform random number distributions via our own
|
||||
[`rand_distr`](https://docs.rs/rand_distr) and via
|
||||
the [`statrs`](https://docs.rs/statrs/0.13.0/statrs/)
|
||||
- Random processes (mostly choose and shuffle) via [`rand::seq`](https://docs.rs/rand/latest/rand/seq/index.html) traits
|
||||
@ -28,19 +28,23 @@ All with:
|
||||
|
||||
- [Portably reproducible output](https://rust-random.github.io/book/portability.html)
|
||||
- `#[no_std]` compatibility (partial)
|
||||
- *Many* performance optimisations
|
||||
- *Many* performance optimisations thanks to contributions from the wide
|
||||
user-base
|
||||
|
||||
It's also worth pointing out what Rand *is not*:
|
||||
Rand **is not**:
|
||||
|
||||
- Small. Most low-level crates are small, but the higher-level `rand` and
|
||||
`rand_distr` each contain a lot of functionality.
|
||||
- Small (LOC). Most low-level crates are small, but the higher-level `rand`
|
||||
and `rand_distr` each contain a lot of functionality.
|
||||
- Simple (implementation). We have a strong focus on correctness, speed and flexibility, but
|
||||
not simplicity. If you prefer a small-and-simple library, there are
|
||||
alternatives including [fastrand](https://crates.io/crates/fastrand)
|
||||
and [oorandom](https://crates.io/crates/oorandom).
|
||||
- Slow. We take performance seriously, with considerations also for set-up
|
||||
time of new distributions, commonly-used parameters, and parameters of the
|
||||
current sampler.
|
||||
- A cryptography library. Rand provides functionality for generating
|
||||
unpredictable random data (potentially applicable depending on requirements)
|
||||
but does not provide high-level cryptography functionality.
|
||||
|
||||
Rand is a community project and cannot provide legally-binding guarantees of
|
||||
security.
|
||||
|
||||
Documentation:
|
||||
|
||||
|
43
SECURITY.md
43
SECURITY.md
@ -1,31 +1,46 @@
|
||||
# Security Policy
|
||||
|
||||
## No guarantees
|
||||
## Disclaimer
|
||||
|
||||
Support is provided on a best-effort bases only.
|
||||
No binding guarantees can be provided.
|
||||
Rand is a community project and cannot provide legally-binding guarantees of
|
||||
security.
|
||||
|
||||
## Security premises
|
||||
|
||||
Rand provides the trait `rand_core::CryptoRng` aka `rand::CryptoRng` as a marker
|
||||
trait. Generators implementing `RngCore` *and* `CryptoRng`, and given the
|
||||
additional constraints that:
|
||||
### Marker traits
|
||||
|
||||
Rand provides the marker traits `CryptoRng`, `TryCryptoRng` and
|
||||
`CryptoBlockRng`. Generators implementing one of these traits and used in a way
|
||||
which meets the following additional constraints:
|
||||
|
||||
- Instances of seedable RNGs (those implementing `SeedableRng`) are
|
||||
constructed with cryptographically secure seed values
|
||||
- The state (memory) of the RNG and its seed value are not be exposed
|
||||
- The state (memory) of the RNG and its seed value are not exposed
|
||||
|
||||
are expected to provide the following:
|
||||
|
||||
- An attacker can gain no advantage over chance (50% for each bit) in
|
||||
predicting the RNG output, even with full knowledge of all prior outputs.
|
||||
- An attacker cannot predict the output with more accuracy than what would be
|
||||
expected through pure chance since each possible output value of any method
|
||||
under the above traits which generates output bytes (including
|
||||
`RngCore::next_u32`, `RngCore::next_u64`, `RngCore::fill_bytes`,
|
||||
`TryRngCore::try_next_u32`, `TryRngCore::try_next_u64`,
|
||||
`TryRngCore::try_fill_bytes` and `BlockRngCore::generate`) should be equally
|
||||
likely
|
||||
- Knowledge of prior outputs from the generator does not aid an attacker in
|
||||
predicting future outputs
|
||||
|
||||
For some RNGs, notably `OsRng`, `ThreadRng` and those wrapped by `ReseedingRng`,
|
||||
we provide limited mitigations against side-channel attacks:
|
||||
### Specific generators
|
||||
|
||||
- After the state (memory) of an RNG is leaked, there is an upper-bound on the
|
||||
number of bits of output by the RNG before prediction of output by an
|
||||
observer again becomes computationally-infeasible
|
||||
`OsRng` is a stateless "generator" implemented via [getrandom]. As such, it has
|
||||
no possible state to leak and cannot be improperly seeded.
|
||||
|
||||
`ThreadRng` will periodically reseed itself, thus placing an upper bound on the
|
||||
number of bits of output from an instance before any advantage an attacker may
|
||||
have gained through state-compromising side-channel attacks is lost.
|
||||
|
||||
[getrandom]: https://crates.io/crates/getrandom
|
||||
|
||||
### Distributions
|
||||
|
||||
Additionally, derivations from such an RNG (including the `Rng` trait,
|
||||
implementations of the `Distribution` trait, and `seq` algorithms) should not
|
||||
|
@ -11,10 +11,9 @@
|
||||
use crate::{TryCryptoRng, TryRngCore};
|
||||
use getrandom::getrandom;
|
||||
|
||||
/// A random number generator that retrieves randomness from the
|
||||
/// operating system.
|
||||
/// An interface over the operating-system's random data source
|
||||
///
|
||||
/// This is a zero-sized struct. It can be freely constructed with `OsRng`.
|
||||
/// This is a zero-sized struct. It can be freely constructed with just `OsRng`.
|
||||
///
|
||||
/// The implementation is provided by the [getrandom] crate. Refer to
|
||||
/// [getrandom] documentation for details.
|
||||
@ -32,7 +31,8 @@ use getrandom::getrandom;
|
||||
///
|
||||
/// After the first successful call, it is highly unlikely that failures or
|
||||
/// significant delays will occur (although performance should be expected to
|
||||
/// be much slower than a user-space PRNG).
|
||||
/// be much slower than a user-space
|
||||
/// [PRNG](https://rust-random.github.io/book/guide-gen.html#pseudo-random-number-generators)).
|
||||
///
|
||||
/// # Usage example
|
||||
/// ```
|
||||
|
@ -11,17 +11,7 @@
|
||||
//!
|
||||
//! [`Uniform`] is the standard distribution to sample uniformly from a range;
|
||||
//! e.g. `Uniform::new_inclusive(1, 6).unwrap()` can sample integers from 1 to 6, like a
|
||||
//! standard die. [`Rng::random_range`] supports any type supported by [`Uniform`].
|
||||
//!
|
||||
//! This distribution is provided with support for several primitive types
|
||||
//! (all integer and floating-point types) as well as [`std::time::Duration`],
|
||||
//! and supports extension to user-defined types via a type-specific *back-end*
|
||||
//! implementation.
|
||||
//!
|
||||
//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the
|
||||
//! back-ends supporting sampling from primitive integer and floating-point
|
||||
//! ranges as well as from [`std::time::Duration`]; these types do not normally
|
||||
//! need to be used directly (unless implementing a derived back-end).
|
||||
//! standard die. [`Rng::random_range`] is implemented over [`Uniform`].
|
||||
//!
|
||||
//! # Example usage
|
||||
//!
|
||||
@ -151,26 +141,38 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Sample values uniformly between two bounds.
|
||||
///
|
||||
/// # Construction
|
||||
///
|
||||
/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform
|
||||
/// distribution sampling from the given range; these functions may do extra
|
||||
/// work up front to make sampling of multiple values faster. If only one sample
|
||||
/// from the range is required, [`Rng::random_range`] can be more efficient.
|
||||
/// distribution sampling from the given `low` and `high` limits. `Uniform` may
|
||||
/// also be constructed via [`TryFrom`] as in `Uniform::try_from(1..=6).unwrap()`.
|
||||
///
|
||||
/// Constructors may do extra work up front to allow faster sampling of multiple
|
||||
/// values. Where only a single sample is required it is suggested to use
|
||||
/// [`Rng::random_range`] or one of the `sample_single` methods instead.
|
||||
///
|
||||
/// When sampling from a constant range, many calculations can happen at
|
||||
/// compile-time and all methods should be fast; for floating-point ranges and
|
||||
/// the full range of integer types, this should have comparable performance to
|
||||
/// the `Standard` distribution.
|
||||
///
|
||||
/// Steps are taken to avoid bias, which might be present in naive
|
||||
/// implementations; for example `rng.gen::<u8>() % 170` samples from the range
|
||||
/// `[0, 169]` but is twice as likely to select numbers less than 85 than other
|
||||
/// values. Further, the implementations here give more weight to the high-bits
|
||||
/// generated by the RNG than the low bits, since with some RNGs the low-bits
|
||||
/// are of lower quality than the high bits.
|
||||
/// # Provided implementations
|
||||
///
|
||||
/// Implementations must sample in `[low, high)` range for
|
||||
/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular, care must
|
||||
/// be taken to ensure that rounding never results values `< low` or `>= high`.
|
||||
/// - `char` ([`UniformChar`]): samples a range over the implementation for `u32`
|
||||
/// - `f32`, `f64` ([`UniformFloat`]): samples approximately uniformly within a
|
||||
/// range; bias may be present in the least-significant bit of the significand
|
||||
/// and the limits of the input range may be sampled even when an open
|
||||
/// (exclusive) range is used
|
||||
/// - Integer types ([`UniformInt`]) may show a small bias relative to the
|
||||
/// expected uniform distribution of output. In the worst case, bias affects
|
||||
/// 1 in `2^n` samples where n is 56 (`i8` and `u8`), 48 (`i16` and `u16`), 96
|
||||
/// (`i32` and `u32`), 64 (`i64` and `u64`), 128 (`i128` and `u128`).
|
||||
/// The `unbiased` feature flag fixes this bias.
|
||||
/// - `usize` ([`UniformUsize`]) is handled specially, using the `u32`
|
||||
/// implementation where possible to enable portable results across 32-bit and
|
||||
/// 64-bit CPU architectures.
|
||||
/// - `Duration` ([`UniformDuration`]): samples a range over the implementation
|
||||
/// for `u32` or `u64`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -29,14 +29,17 @@ use serde::{Deserialize, Serialize};
|
||||
///
|
||||
/// # Implementation notes
|
||||
///
|
||||
/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the
|
||||
/// `UniformFloat` implementation converts the output of an PRNG itself. This
|
||||
/// way one or two steps can be optimized out.
|
||||
/// `UniformFloat` implementations convert RNG output to a float in the range
|
||||
/// `[1, 2)` via transmutation, map this to `[0, 1)`, then scale and translate
|
||||
/// to the desired range. Values produced this way have what equals 23 bits of
|
||||
/// random digits for an `f32` and 52 for an `f64`.
|
||||
///
|
||||
/// The floats are first converted to a value in the `[1, 2)` interval using a
|
||||
/// transmute-based method, and then mapped to the expected range with a
|
||||
/// multiply and addition. Values produced this way have what equals 23 bits of
|
||||
/// random digits for an `f32`, and 52 for an `f64`.
|
||||
/// # Bias and range errors
|
||||
///
|
||||
/// Bias may be expected within the least-significant bit of the significand.
|
||||
/// It is not guaranteed that exclusive limits of a range are respected; i.e.
|
||||
/// when sampling the range `[a, b)` it is not guaranteed that `b` is never
|
||||
/// sampled.
|
||||
///
|
||||
/// [`new`]: UniformSampler::new
|
||||
/// [`new_inclusive`]: UniformSampler::new_inclusive
|
||||
|
@ -58,6 +58,13 @@ use serde::{Deserialize, Serialize};
|
||||
/// multiply by `range`, the result is in the high word. Then comparing the low
|
||||
/// word against `zone` makes sure our distribution is uniform.
|
||||
///
|
||||
/// # Bias
|
||||
///
|
||||
/// Unless the `unbiased` feature flag is used, outputs may have a small bias.
|
||||
/// In the worst case, bias affects 1 in `2^n` samples where n is
|
||||
/// 56 (`i8` and `u8`), 48 (`i16` and `u16`), 96 (`i32` and `u32`), 64 (`i64`
|
||||
/// and `u64`), 128 (`i128` and `u128`).
|
||||
///
|
||||
/// [`Uniform`]: super::Uniform
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
|
@ -41,16 +41,36 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
|
||||
/// A reference to the thread-local generator
|
||||
///
|
||||
/// This type is a reference to a lazily-initialized thread-local generator.
|
||||
/// An instance can be obtained via [`rand::rng()`][crate::rng())] or via
|
||||
/// `ThreadRng::default()`.
|
||||
/// An instance can be obtained via [`rand::rng()`][crate::rng()] or via
|
||||
/// [`ThreadRng::default()`].
|
||||
/// The handle cannot be passed between threads (is not `Send` or `Sync`).
|
||||
///
|
||||
/// `ThreadRng` uses the same CSPRNG as [`StdRng`], ChaCha12. As with
|
||||
/// [`StdRng`], the algorithm may be changed, subject to reasonable expectations
|
||||
/// of security and performance.
|
||||
/// # Security
|
||||
///
|
||||
/// `ThreadRng` is automatically seeded from [`OsRng`] with periodic reseeding
|
||||
/// (every 64 kiB — see [`ReseedingRng`] documentation for details).
|
||||
/// Security must be considered relative to a threat model and validation
|
||||
/// requirements. The Rand project can provide no guarantee of fitness for
|
||||
/// purpose. The design criteria for `ThreadRng` are as follows:
|
||||
///
|
||||
/// - Automatic seeding via [`OsRng`] and periodically thereafter (see
|
||||
/// ([`ReseedingRng`] documentation). Limitation: there is no automatic
|
||||
/// reseeding on process fork (see [below](#fork)).
|
||||
/// - A rigorusly analyzed, unpredictable (cryptographic) pseudo-random generator
|
||||
/// (see [the book on security](https://rust-random.github.io/book/guide-rngs.html#security)).
|
||||
/// The currently selected algorithm is ChaCha (12-rounds).
|
||||
/// See also [`StdRng`] documentation.
|
||||
/// - Not to leak internal state through [`Debug`] or serialization
|
||||
/// implementations.
|
||||
/// - No further protections exist to in-memory state. In particular, the
|
||||
/// implementation is not required to zero memory on exit (of the process or
|
||||
/// thread). (This may change in the future.)
|
||||
/// - Be fast enough for general-purpose usage. Note in particular that
|
||||
/// `ThreadRng` is designed to be a "fast, reasonably secure generator"
|
||||
/// (where "reasonably secure" implies the above criteria).
|
||||
///
|
||||
/// We leave it to the user to determine whether this generator meets their
|
||||
/// security requirements. For an alternative, see [`OsRng`].
|
||||
///
|
||||
/// # Fork
|
||||
///
|
||||
/// `ThreadRng` is not automatically reseeded on fork. It is recommended to
|
||||
/// explicitly call [`ThreadRng::reseed`] immediately after a fork, for example:
|
||||
@ -68,13 +88,6 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
|
||||
/// from an interrupt (e.g. a fork handler) unless it can be guaranteed that no
|
||||
/// other method on the same `ThreadRng` is currently executing.
|
||||
///
|
||||
/// Security must be considered relative to a threat model and validation
|
||||
/// requirements. `ThreadRng` attempts to meet basic security considerations
|
||||
/// for producing unpredictable random numbers: use a CSPRNG, use a
|
||||
/// recommended platform-specific seed ([`OsRng`]), and avoid
|
||||
/// leaking internal secrets e.g. via [`Debug`] implementation or serialization.
|
||||
/// Memory is not zeroized on drop.
|
||||
///
|
||||
/// [`ReseedingRng`]: crate::rngs::ReseedingRng
|
||||
/// [`StdRng`]: crate::rngs::StdRng
|
||||
#[derive(Clone)]
|
||||
@ -115,9 +128,9 @@ thread_local!(
|
||||
}
|
||||
);
|
||||
|
||||
/// Access a local, pre-initialized generator
|
||||
/// Access a fast, pre-initialized generator
|
||||
///
|
||||
/// This is a reasonably fast unpredictable thread-local instance of [`ThreadRng`].
|
||||
/// This is a handle to the local [`ThreadRng`].
|
||||
///
|
||||
/// See also [`crate::rngs`] for alternatives.
|
||||
///
|
||||
@ -139,6 +152,10 @@ thread_local!(
|
||||
/// println!("A simulated die roll: {}", rng.random_range(1..=6));
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # Security
|
||||
///
|
||||
/// Refer to [`ThreadRng#Security`].
|
||||
pub fn rng() -> ThreadRng {
|
||||
let rng = THREAD_RNG_KEY.with(|t| t.clone());
|
||||
ThreadRng { rng }
|
||||
|
Loading…
x
Reference in New Issue
Block a user