1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! # mod-rand
//!
//! Tiered random number generation for Rust. Zero dependencies. Pick
//! the tier appropriate to your threat model.
//!
//! ## Tiers
//!
//! Each tier is also available under a plain name. The plain names
//! are the same modules, so mixing them is fine.
//!
//! - **[`secure`]** (same as [`tier3`]): OS-backed cryptographic
//! random. The only choice for tokens, passwords, keys, session
//! IDs, and temp names in shared directories. Calls platform
//! syscalls directly.
//! - **[`unique`]** (same as [`tier2`]): process-unique values derived
//! from PID + time + counter. For request IDs, log correlation, and
//! names in private directories. Fast enough for high-frequency use.
//! Predictable, so never a token or a password.
//! - **[`seeded`]** (same as [`tier1`]): deterministic seedable PRNG
//! (xoshiro256\*\*). For simulation, fixture data, non-security
//! shuffling. Always available, works in `no_std`. Reproducible
//! from its seed, so never a token or a password.
//!
//! ## Quick example
//!
//! Raw draws:
//!
//! ```
//! use mod_rand::tier1::Xoshiro256;
//!
//! let mut rng = Xoshiro256::seed_from_u64(42);
//! let n: u64 = rng.next_u64();
//! # let _ = n;
//! ```
//!
//! Bounded ranges — every tier exposes a parallel `gen_range_*` /
//! `range_*` / `random_range_*` family that uses Lemire's "Nearly
//! Divisionless" rejection sampling under the hood, so output is
//! uniformly distributed with no modulo bias:
//!
//! ```
//! use mod_rand::tier1::Xoshiro256;
//!
//! let mut rng = Xoshiro256::seed_from_u64(42);
//!
//! // Half-open: never returns 100.
//! let pct: u32 = rng.gen_range_u32(0..100);
//!
//! // Inclusive: classic six-sided die.
//! let d6: u32 = rng.gen_range_inclusive_u32(1..=6);
//! # let _ = (pct, d6);
//! ```
//!
//! The same `..` (half-open) vs `..=` (inclusive) convention applies
//! on Tier 2 (free functions) and Tier 3 (free functions returning
//! `io::Result`):
//!
//! ```no_run
//! # #[cfg(all(feature = "tier2", feature = "tier3"))]
//! # fn demo() -> std::io::Result<()> {
//! use mod_rand::{tier2, tier3};
//!
//! let id = tier2::range_inclusive_u32(1..=1_000);
//! let key = tier3::random_range_inclusive_u64(0..=u64::MAX)?;
//! # let _ = (id, key);
//! # Ok(())
//! # }
//! ```
//!
//! ## Choosing a tier
//!
//! | Use case | Module |
//! |--------------------------------------------------|---------------------|
//! | Test fixtures, simulation | `seeded` (tier 1) |
//! | Request IDs, names in a private directory | `unique` (tier 2) |
//! | Tokens, passwords, session IDs, keys, salts | `secure` (tier 3) |
//! | Temp file or directory names in `/tmp` | `secure` (tier 3) |
//!
//! If an attacker could gain anything by predicting the value, use
//! `secure`.
//!
//! ```
//! # #[cfg(feature = "tier3")]
//! # fn demo() -> std::io::Result<()> {
//! let token = mod_rand::secure::random_alphanumeric(32)?;
//! let key = mod_rand::secure::random_bytes(32)?;
//! # let _ = (token, key);
//! # Ok(())
//! # }
//! ```
//!
//! ## Status
//!
//! `1.x` is API-stable under SemVer: full xoshiro256\*\* with
//! splitmix64 seeding (tier 1), Stafford-mix-13 over (PID + nanos +
//! atomic counter + per-process salt) (tier 2), and direct platform
//! syscalls for tier 3 (`getrandom(2)` / `BCryptGenRandom` /
//! `getentropy(3)`). All bounded-range methods use Lemire's
//! "Nearly Divisionless" rejection sampling, verified for uniformity
//! by 1,000,000-draw chi-squared tests at the integration level.
//! See the [CHANGELOG](https://github.com/jamesgober/mod-rand/blob/main/CHANGELOG.md)
//! for release history.
/// OS-backed cryptographic random: the same module as [`tier3`].
///
/// The plain name for the tier to use for tokens, passwords, keys,
/// session IDs, salts, and names in shared directories.
///
/// ```
/// let token = mod_rand::secure::random_hex(16)?;
/// assert_eq!(token.len(), 32);
/// # Ok::<(), std::io::Error>(())
/// ```
/// Process-unique values: the same module as [`tier2`].
///
/// Predictable to anyone who has seen earlier values, so never a
/// token, a password, or a key; see [`tier2`] for what it is good for.
/// The deprecated `tier2::random_*` string functions are not
/// re-exported here.
///
/// ```
/// let id = mod_rand::unique::unique_hex(16);
/// assert_eq!(id.len(), 16);
/// ```
///
/// The tier 2 string functions warn when used, because they share
/// names with the secure ones:
///
/// ```compile_fail
/// #![deny(deprecated)]
/// let _ = mod_rand::tier2::random_alphanumeric(16);
/// ```
/// Deterministic seedable PRNG: the same module as [`tier1`].
///
/// Reproducible from its seed, so never a token, a password, or a key.
///
/// ```
/// let mut rng = mod_rand::seeded::Xoshiro256::seed_from_u64(42);
/// let _ = rng.next_u64();
/// ```