entropy/rng/mod.rs
1//! [`Rng`] trait and all generator implementations used by the test suite.
2
3pub mod aes_ctr;
4pub mod bad;
5pub mod block_ctr;
6pub mod c_stdlib;
7pub mod chacha20_rng;
8pub mod crypto_cprng;
9pub mod dual_ec;
10pub mod hash_drbg;
11pub mod hmac_drbg;
12pub mod lcg;
13pub mod mt19937;
14pub mod os;
15pub mod pcg;
16pub mod sfc;
17pub mod spongebob;
18pub mod squidward;
19pub mod stream_rng;
20pub mod wyrand;
21pub mod xorshift;
22pub mod xoshiro;
23
24pub use aes_ctr::AesCtr;
25pub use bad::{ConstantRng, CounterRng};
26pub use block_ctr::BlockCtrRng;
27pub use c_stdlib::{
28 BsdRandCompat, BsdRandom, CRand, LinuxLibcRandom, Rand48, SystemVRand, WindowsDotNetRandom,
29 WindowsMsvcRand, WindowsVb6Rnd,
30};
31pub use chacha20_rng::ChaCha20Rng;
32pub use crypto_cprng::CryptoCtrDrbg;
33pub use dual_ec::DualEcDrbg;
34pub use hash_drbg::HashDrbg;
35pub use hmac_drbg::HmacDrbg;
36pub use lcg::{Lcg32, LcgVariant};
37pub use mt19937::Mt19937;
38pub use os::OsRng;
39pub use pcg::{Pcg32, Pcg64};
40pub use sfc::{Jsf64, Sfc64};
41pub use spongebob::SpongeBob;
42pub use squidward::Squidward;
43pub use stream_rng::StreamRng;
44pub use wyrand::WyRand;
45pub use xorshift::{Xorshift32, Xorshift64};
46pub use xoshiro::{Xoroshiro128, Xoshiro256};
47
48// ── Rng trait ─────────────────────────────────────────────────────────────────
49
50/// Minimal interface required by every test.
51///
52/// All tests consume bits or 32-bit words; the trait methods below are the
53/// only ones needed. Blanket impls fill in the derived methods.
54///
55/// ## Design note — no CSPRNG marker type
56///
57/// This trait is intentionally flat: every generator from `ConstantRng` to
58/// `ChaCha20Rng` implements the same `Rng`. This is correct for a test
59/// harness whose job is to compare generators uniformly, but it means the
60/// **type system provides no barrier** against substituting a weak generator
61/// where a strong one is required. Any function that accepts `impl Rng` will
62/// silently compile with `ConstantRng` or `SystemVRand`.
63///
64/// **Do not copy this design into production code.** In an application,
65/// define a separate `CsprngRng: Rng` marker subtrait (or a newtype) and
66/// restrict security-sensitive functions to `impl CsprngRng` so that weak
67/// generators are rejected at compile time.
68///
69/// ## Byte and word ordering contract
70///
71/// * **`next_u64` default** — assembles two `next_u32` calls with the *first*
72/// call becoming the **high** 32 bits: `(hi << 32) | lo`. Generators that
73/// override this (e.g. byte-backed DRBG adapters) may emit a different
74/// interleaving; those overrides are documented on the concrete type.
75///
76/// * **`collect_bits`** — extracts bits **LSB-first** from each 32-bit word:
77/// bit 0 of word 0 is the first element of the returned slice.
78///
79/// * **Byte-backed generators** (HMAC_DRBG, Hash_DRBG, ChaCha20, Squidward)
80/// expose a little-endian byte stream: `next_u32` reads 4 bytes in LE order,
81/// `next_u64` reads 8 bytes in LE order, independently of the default
82/// `next_u64` above. Mixing `next_u32` and `next_u64` at a buffer refill
83/// boundary silently discards up to 7 trailing bytes; see the individual
84/// adapter doc comments for the full caveat.
85pub trait Rng {
86 /// Return the next 32-bit pseudo-random word.
87 fn next_u32(&mut self) -> u32;
88
89 /// Return the next 64-bit pseudo-random word.
90 ///
91 /// Default: two `next_u32` calls, first call → high 32 bits.
92 /// Byte-backed generators override this to read 8 LE bytes directly.
93 fn next_u64(&mut self) -> u64 {
94 ((self.next_u32() as u64) << 32) | (self.next_u32() as u64)
95 }
96
97 /// Uniform float in \[0, 1) built from **32 bits** of the generator's output.
98 ///
99 /// This default always calls `next_u32`, even for generators that natively
100 /// produce 64-bit output (PCG64, Xoshiro256, ChaCha20Rng, etc.). Those
101 /// generators' upper 32 bits are discarded, so `next_f64` never delivers
102 /// more than 2³² distinct values regardless of the underlying generator.
103 /// For the statistical tests in this crate (which use floats only for
104 /// p-value lookup) this is fine. Do not use `next_f64` to sample
105 /// high-precision distributions from a 64-bit generator.
106 fn next_f64(&mut self) -> f64 {
107 self.next_u32() as f64 * (1.0 / 4_294_967_296.0)
108 }
109
110 /// Collect `n` bits as `Vec<u8>` values 0 or 1, LSB-first from each word.
111 fn collect_bits(&mut self, n: usize) -> Vec<u8> {
112 let mut bits = Vec::with_capacity(n);
113 let mut remaining = n;
114 while remaining > 0 {
115 let word = self.next_u32();
116 let take = remaining.min(32);
117 for i in 0..take {
118 bits.push(((word >> i) & 1) as u8);
119 }
120 remaining -= take;
121 }
122 bits
123 }
124
125 /// Collect `n` 32-bit words.
126 fn collect_u32s(&mut self, n: usize) -> Vec<u32> {
127 (0..n).map(|_| self.next_u32()).collect()
128 }
129
130 /// Collect `n` floats in \[0, 1).
131 fn collect_f64s(&mut self, n: usize) -> Vec<f64> {
132 (0..n).map(|_| self.next_f64()).collect()
133 }
134}