Skip to content

Commit ba7f515

Browse files
authored
Revise RNG docs; enable small_rng by default (#1455)
1 parent defeb0c commit ba7f515

File tree

6 files changed

+153
-122
lines changed

6 files changed

+153
-122
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
1414
- Rename `Rng::gen` to `Rng::random` to avoid conflict with the new `gen` keyword in Rust 2024 (#1435)
1515
- Move all benchmarks to new `benches` crate (#1439)
1616
- Annotate panicking methods with `#[track_caller]` (#1442, #1447)
17+
- Enable feature `small_rng` by default (#1455)
1718

1819
## [0.9.0-alpha.1] - 2024-03-18
1920
- Add the `Slice::num_choices` method to the Slice distribution (#1402)

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ features = ["small_rng", "serde1"]
2828

2929
[features]
3030
# Meta-features:
31-
default = ["std", "std_rng", "getrandom"]
31+
default = ["std", "std_rng", "getrandom", "small_rng"]
3232
nightly = [] # some additions requiring nightly Rust
3333
serde1 = ["serde", "rand_core/serde1"]
3434

rand_distr/tests/pdf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#![allow(clippy::float_cmp)]
1010

1111
use average::Histogram;
12-
use rand::Rng;
12+
use rand::{Rng, SeedableRng};
1313
use rand_distr::{Normal, SkewNormal};
1414

1515
const HIST_LEN: usize = 100;

src/rngs/mod.rs

Lines changed: 45 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,82 +8,61 @@
88

99
//! Random number generators and adapters
1010
//!
11-
//! ## Background: Random number generators (RNGs)
11+
//! This crate provides a small selection of non-[portable] generators.
12+
//! See also [Types of generators] and [Our RNGs] in the book.
1213
//!
13-
//! Computers cannot produce random numbers from nowhere. We classify
14-
//! random number generators as follows:
14+
//! ## Generators
1515
//!
16-
//! - "True" random number generators (TRNGs) use hard-to-predict data sources
17-
//! (e.g. the high-resolution parts of event timings and sensor jitter) to
18-
//! harvest random bit-sequences, apply algorithms to remove bias and
19-
//! estimate available entropy, then combine these bits into a byte-sequence
20-
//! or an entropy pool. This job is usually done by the operating system or
21-
//! a hardware generator (HRNG).
22-
//! - "Pseudo"-random number generators (PRNGs) use algorithms to transform a
23-
//! seed into a sequence of pseudo-random numbers. These generators can be
24-
//! fast and produce well-distributed unpredictable random numbers (or not).
25-
//! They are usually deterministic: given algorithm and seed, the output
26-
//! sequence can be reproduced. They have finite period and eventually loop;
27-
//! with many algorithms this period is fixed and can be proven sufficiently
28-
//! long, while others are chaotic and the period depends on the seed.
29-
//! - "Cryptographically secure" pseudo-random number generators (CSPRNGs)
30-
//! are the sub-set of PRNGs which are secure. Security of the generator
31-
//! relies both on hiding the internal state and using a strong algorithm.
16+
//! This crate provides a small selection of non-[portable] random number generators:
3217
//!
33-
//! ## Traits and functionality
34-
//!
35-
//! All RNGs implement the [`RngCore`] trait, as a consequence of which the
36-
//! [`Rng`] extension trait is automatically implemented. Secure RNGs may
37-
//! additionally implement the [`CryptoRng`] trait.
38-
//!
39-
//! All PRNGs require a seed to produce their random number sequence. The
40-
//! [`SeedableRng`] trait provides three ways of constructing PRNGs:
41-
//!
42-
//! - `from_seed` accepts a type specific to the PRNG
43-
//! - `from_rng` allows a PRNG to be seeded from any other RNG
44-
//! - `seed_from_u64` allows any PRNG to be seeded from a `u64` insecurely
45-
//! - `from_os_rng` securely seeds a PRNG from system randomness source
46-
//!
47-
//! Use the [`rand_core`] crate when implementing your own RNGs.
48-
//!
49-
//! ## Our generators
50-
//!
51-
//! This crate provides several random number generators:
52-
//!
53-
//! - [`OsRng`] is an interface to the operating system's random number
54-
//! source. Typically the operating system uses a CSPRNG with entropy
55-
//! provided by a TRNG and some type of on-going re-seeding.
18+
//! - [`OsRng`] is a stateless interface over the operating system's random number
19+
//! source. This is typically secure with some form of periodic re-seeding.
5620
//! - [`ThreadRng`], provided by the [`thread_rng`] function, is a handle to a
57-
//! thread-local CSPRNG with periodic seeding from [`OsRng`]. Because this
21+
//! thread-local generator with periodic seeding from [`OsRng`]. Because this
5822
//! is local, it is typically much faster than [`OsRng`]. It should be
59-
//! secure, though the paranoid may prefer [`OsRng`].
23+
//! secure, but see documentation on [`ThreadRng`].
6024
//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security
6125
//! (based on reviews, maturity and usage). The current algorithm is ChaCha12,
6226
//! which is well established and rigorously analysed.
63-
//! [`StdRng`] provides the algorithm used by [`ThreadRng`] but without
64-
//! periodic reseeding.
65-
//! - [`SmallRng`] is an **insecure** PRNG designed to be fast, simple, require
66-
//! little memory, and have good output quality.
27+
//! [`StdRng`] is the deterministic generator used by [`ThreadRng`] but
28+
//! without the periodic reseeding or thread-local management.
29+
//! - [`SmallRng`] is a relatively simple, insecure generator designed to be
30+
//! fast, use little memory, and pass various statistical tests of
31+
//! randomness quality.
6732
//!
6833
//! The algorithms selected for [`StdRng`] and [`SmallRng`] may change in any
69-
//! release and may be platform-dependent, therefore they should be considered
70-
//! **not reproducible**.
34+
//! release and may be platform-dependent, therefore they are not
35+
//! [reproducible][portable].
36+
//!
37+
//! ### Additional generators
7138
//!
72-
//! ## Additional generators
39+
//! - The [`rdrand`] crate provides an interface to the RDRAND and RDSEED
40+
//! instructions available in modern Intel and AMD CPUs.
41+
//! - The [`rand_jitter`] crate provides a user-space implementation of
42+
//! entropy harvesting from CPU timer jitter, but is very slow and has
43+
//! [security issues](https://github.com/rust-random/rand/issues/699).
44+
//! - The [`rand_chacha`] crate provides [portable] implementations of
45+
//! generators derived from the [ChaCha] family of stream ciphers
46+
//! - The [`rand_pcg`] crate provides [portable] implementations of a subset
47+
//! of the [PCG] family of small, insecure generators
48+
//! - The [`rand_xoshiro`] crate provides [portable] implementations of the
49+
//! [xoshiro] family of small, insecure generators
7350
//!
74-
//! **TRNGs**: The [`rdrand`] crate provides an interface to the RDRAND and
75-
//! RDSEED instructions available in modern Intel and AMD CPUs.
76-
//! The [`rand_jitter`] crate provides a user-space implementation of
77-
//! entropy harvesting from CPU timer jitter, but is very slow and has
78-
//! [security issues](https://github.com/rust-random/rand/issues/699).
51+
//! For more, search [crates with the `rng` tag].
52+
//!
53+
//! ## Traits and functionality
7954
//!
80-
//! **PRNGs**: Several companion crates are available, providing individual or
81-
//! families of PRNG algorithms. These provide the implementations behind
82-
//! [`StdRng`] and [`SmallRng`] but can also be used directly, indeed *should*
83-
//! be used directly when **reproducibility** matters.
84-
//! Some suggestions are: [`rand_chacha`], [`rand_pcg`], [`rand_xoshiro`].
85-
//! A full list can be found by searching for crates with the [`rng` tag].
55+
//! All generators implement [`RngCore`] and thus also [`Rng`][crate::Rng].
56+
//! See also the [Random Values] chapter in the book.
57+
//!
58+
//! Secure RNGs may additionally implement the [`CryptoRng`] trait.
59+
//!
60+
//! Use the [`rand_core`] crate when implementing your own RNGs.
8661
//!
62+
//! [portable]: https://rust-random.github.io/book/crate-reprod.html
63+
//! [Types of generators]: https://rust-random.github.io/book/guide-gen.html
64+
//! [Our RNGs]: https://rust-random.github.io/book/guide-rngs.html
65+
//! [Random Values]: https://rust-random.github.io/book/guide-values.html
8766
//! [`Rng`]: crate::Rng
8867
//! [`RngCore`]: crate::RngCore
8968
//! [`CryptoRng`]: crate::CryptoRng
@@ -94,7 +73,10 @@
9473
//! [`rand_chacha`]: https://crates.io/crates/rand_chacha
9574
//! [`rand_pcg`]: https://crates.io/crates/rand_pcg
9675
//! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
97-
//! [`rng` tag]: https://crates.io/keywords/rng
76+
//! [crates with the `rng` tag]: https://crates.io/keywords/rng
77+
//! [chacha]: https://cr.yp.to/chacha.html
78+
//! [PCG]: https://www.pcg-random.org/
79+
//! [xoshiro]: https://prng.di.unimi.it/
9880
9981
mod reseeding;
10082
pub use reseeding::ReseedingRng;

src/rngs/small.rs

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,86 @@ type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
1515
#[cfg(not(target_pointer_width = "64"))]
1616
type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
1717

18-
/// A small-state, fast non-crypto PRNG
18+
/// A small-state, fast, non-crypto, non-portable PRNG
1919
///
20-
/// `SmallRng` may be a good choice when a PRNG with small state, cheap
21-
/// initialization, good statistical quality and good performance are required.
22-
/// Note that depending on the application, [`StdRng`] may be faster on many
23-
/// modern platforms while providing higher-quality randomness. Furthermore,
24-
/// `SmallRng` is **not** a good choice when:
20+
/// This is the "standard small" RNG, a generator with the following properties:
2521
///
26-
/// - Portability is required. Its implementation is not fixed. Use a named
27-
/// generator from an external crate instead, for example [rand_xoshiro] or
28-
/// [rand_chacha]. Refer also to
29-
/// [The Book](https://rust-random.github.io/book/guide-rngs.html).
30-
/// - Security against prediction is important. Use [`StdRng`] instead.
22+
/// - Non-[portable]: any future library version may replace the algorithm
23+
/// and results may be platform-dependent.
24+
/// (For a small portable generator, use the [rand_pcg] or [rand_xoshiro] crate.)
25+
/// - Non-cryptographic: output is easy to predict (insecure)
26+
/// - [Quality]: statistically good quality
27+
/// - Fast: the RNG is fast for both bulk generation and single values, with
28+
/// consistent cost of method calls
29+
/// - Fast initialization
30+
/// - Small state: little memory usage (current state size is 16-32 bytes
31+
/// depending on platform)
3132
///
32-
/// The PRNG algorithm in `SmallRng` is chosen to be efficient on the current
33-
/// platform, without consideration for cryptography or security. The size of
34-
/// its state is much smaller than [`StdRng`]. The current algorithm is
33+
/// The current algorithm is
3534
/// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
3635
/// platforms. Both are also implemented by the [rand_xoshiro] crate.
3736
///
37+
/// ## Seeding (construction)
38+
///
39+
/// This generator implements the [`SeedableRng`] trait. All methods are
40+
/// suitable for seeding, but note that, even with a fixed seed, output is not
41+
/// [portable]. Some suggestions:
42+
///
43+
/// 1. Seed **from an integer** via `seed_from_u64`. This uses a hash function
44+
/// internally to yield a (typically) good seed from any input.
45+
/// ```
46+
/// # use rand::{SeedableRng, rngs::SmallRng};
47+
/// let rng = SmallRng::seed_from_u64(1);
48+
/// # let _: SmallRng = rng;
49+
/// ```
50+
/// 2. With a fresh seed, **direct from the OS** (implies a syscall):
51+
/// ```
52+
/// # use rand::{SeedableRng, rngs::SmallRng};
53+
/// let rng = SmallRng::from_os_rng();
54+
/// # let _: SmallRng = rng;
55+
/// ```
56+
/// 3. Via [`SmallRng::from_thread_rng`]:
57+
/// ```
58+
/// # use rand::rngs::SmallRng;
59+
/// let rng = SmallRng::from_thread_rng();
60+
/// ```
61+
///
62+
/// See also [Seeding RNGs] in the book.
63+
///
64+
/// ## Generation
65+
///
66+
/// The generators implements [`RngCore`] and thus also [`Rng`][crate::Rng].
67+
/// See also the [Random Values] chapter in the book.
68+
///
69+
/// [portable]: https://rust-random.github.io/book/crate-reprod.html
70+
/// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
71+
/// [Random Values]: https://rust-random.github.io/book/guide-values.html
72+
/// [Quality]: https://rust-random.github.io/book/guide-rngs.html#quality
3873
/// [`StdRng`]: crate::rngs::StdRng
39-
/// [rand_chacha]: https://crates.io/crates/rand_chacha
74+
/// [rand_pcg]: https://crates.io/crates/rand_pcg
4075
/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
76+
/// [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html
4177
#[derive(Clone, Debug, PartialEq, Eq)]
4278
pub struct SmallRng(Rng);
4379

80+
impl SeedableRng for SmallRng {
81+
// Fix to 256 bits. Changing this is a breaking change!
82+
type Seed = [u8; 32];
83+
84+
#[inline(always)]
85+
fn from_seed(seed: Self::Seed) -> Self {
86+
// With MSRV >= 1.77: let seed = *seed.first_chunk().unwrap();
87+
const LEN: usize = core::mem::size_of::<<Rng as SeedableRng>::Seed>();
88+
let seed = (&seed[..LEN]).try_into().unwrap();
89+
SmallRng(Rng::from_seed(seed))
90+
}
91+
92+
#[inline(always)]
93+
fn seed_from_u64(state: u64) -> Self {
94+
SmallRng(Rng::seed_from_u64(state))
95+
}
96+
}
97+
4498
impl RngCore for SmallRng {
4599
#[inline(always)]
46100
fn next_u32(&mut self) -> u32 {
@@ -61,21 +115,6 @@ impl RngCore for SmallRng {
61115
rand_core::impl_try_rng_from_rng_core!(SmallRng);
62116

63117
impl SmallRng {
64-
/// Construct an instance seeded from another `Rng`
65-
///
66-
/// We recommend that the source (master) RNG uses a different algorithm
67-
/// (i.e. is not `SmallRng`) to avoid correlations between the child PRNGs.
68-
///
69-
/// # Example
70-
/// ```
71-
/// # use rand::rngs::SmallRng;
72-
/// let rng = SmallRng::from_rng(rand::thread_rng());
73-
/// ```
74-
#[inline(always)]
75-
pub fn from_rng<R: RngCore>(rng: R) -> Self {
76-
Self(Rng::from_rng(rng))
77-
}
78-
79118
/// Construct an instance seeded from the thread-local RNG
80119
///
81120
/// # Panics
@@ -89,24 +128,4 @@ impl SmallRng {
89128
crate::thread_rng().fill_bytes(seed.as_mut());
90129
SmallRng(Rng::from_seed(seed))
91130
}
92-
93-
/// Construct an instance from a `u64` seed
94-
///
95-
/// This provides a convenient method of seeding a `SmallRng` from a simple
96-
/// number by use of another algorithm to mutate and expand the input.
97-
/// This is suitable for use with low Hamming Weight numbers like 0 and 1.
98-
///
99-
/// **Warning:** the implementation is deterministic but not portable:
100-
/// output values may differ according to platform and may be changed by a
101-
/// future version of the library.
102-
///
103-
/// # Example
104-
/// ```
105-
/// # use rand::rngs::SmallRng;
106-
/// let rng = SmallRng::seed_from_u64(1);
107-
/// ```
108-
#[inline(always)]
109-
pub fn seed_from_u64(state: u64) -> Self {
110-
SmallRng(Rng::seed_from_u64(state))
111-
}
112131
}

src/rngs/std.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,48 @@ pub(crate) use rand_chacha::ChaCha12Core as Core;
1515

1616
use rand_chacha::ChaCha12Rng as Rng;
1717

18-
/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
19-
/// on the current platform, to be statistically strong and unpredictable
20-
/// (meaning a cryptographically secure PRNG).
18+
/// A strong, fast (amortized), non-portable RNG
19+
///
20+
/// This is the "standard" RNG, a generator with the following properties:
21+
///
22+
/// - Non-[portable]: any future library version may replace the algorithm
23+
/// and results may be platform-dependent.
24+
/// (For a portable version, use the [rand_chacha] crate directly.)
25+
/// - [CSPRNG]: statistically good quality of randomness and [unpredictable]
26+
/// - Fast ([amortized](https://en.wikipedia.org/wiki/Amortized_analysis)):
27+
/// the RNG is fast for bulk generation, but the cost of method calls is not
28+
/// consistent due to usage of an output buffer.
2129
///
2230
/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
2331
/// see this relevant [rand issue] for the discussion. This may change as new
2432
/// evidence of cipher security and performance becomes available.
2533
///
26-
/// The algorithm is deterministic but should not be considered reproducible
27-
/// due to dependence on configuration and possible replacement in future
28-
/// library versions. For a secure reproducible generator, we recommend use of
29-
/// the [rand_chacha] crate directly.
34+
/// ## Seeding (construction)
35+
///
36+
/// This generator implements the [`SeedableRng`] trait. Any method may be used,
37+
/// but note that `seed_from_u64` is not suitable for usage where security is
38+
/// important. Also note that, even with a fixed seed, output is not [portable].
39+
///
40+
/// It is suggested to use a fresh seed **direct from the OS** as the most
41+
/// secure and convenient option:
42+
/// ```
43+
/// # use rand::{SeedableRng, rngs::StdRng};
44+
/// let rng = StdRng::from_os_rng();
45+
/// # let _: StdRng = rng;
46+
/// ```
47+
///
48+
/// See also [Seeding RNGs] in the book.
49+
///
50+
/// ## Generation
51+
///
52+
/// The generators implements [`RngCore`] and thus also [`Rng`][crate::Rng].
53+
/// See also the [Random Values] chapter in the book.
3054
///
55+
/// [portable]: https://rust-random.github.io/book/crate-reprod.html
56+
/// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
57+
/// [unpredictable]: https://rust-random.github.io/book/guide-rngs.html#security
58+
/// [Random Values]: https://rust-random.github.io/book/guide-values.html
59+
/// [CSPRNG]: https://rust-random.github.io/book/guide-gen.html#cryptographically-secure-pseudo-random-number-generator
3160
/// [rand_chacha]: https://crates.io/crates/rand_chacha
3261
/// [rand issue]: https://github.com/rust-random/rand/issues/932
3362
#[derive(Clone, Debug, PartialEq, Eq)]

0 commit comments

Comments
 (0)