Coverage Report

Created: 2026-09-01 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rand-0.10.2/src/rngs/std.rs
Line
Count
Source
1
// Copyright 2018 Developers of the Rand project.
2
//
3
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6
// option. This file may not be copied, modified, or distributed
7
// except according to those terms.
8
9
//! The standard RNG
10
11
use core::convert::Infallible;
12
use rand_core::{SeedableRng, TryCryptoRng, TryRng};
13
14
use chacha20::ChaCha12Rng as Rng;
15
16
/// A strong, fast (amortized), non-portable RNG
17
///
18
/// This is the "standard" RNG, a generator with the following properties:
19
///
20
/// - Non-[portable]: any future library version may replace the algorithm
21
///   and results may be platform-dependent.
22
///   (For a portable version, use the [chacha20] crate directly.)
23
/// - [CSPRNG]: statistically good quality of randomness and [unpredictable]
24
/// - Fast ([amortized](https://en.wikipedia.org/wiki/Amortized_analysis)):
25
///   the RNG is fast for bulk generation, but the cost of method calls is not
26
///   consistent due to usage of an output buffer.
27
///
28
/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
29
/// see this relevant [rand issue] for the discussion. This may change as new
30
/// evidence of cipher security and performance becomes available.
31
///
32
/// ## Seeding (construction)
33
///
34
/// This generator implements the [`SeedableRng`] trait. Any method may be used,
35
/// but note that `seed_from_u64` is not suitable for usage where security is
36
/// important. Also note that, even with a fixed seed, output is not [portable].
37
///
38
/// Using a fresh seed **direct from the OS** is the most secure option:
39
/// ```
40
/// # use rand::{SeedableRng, rngs::{StdRng, SysRng}};
41
/// let rng = StdRng::try_from_rng(&mut SysRng).unwrap();
42
/// # let _: StdRng = rng;
43
/// ```
44
///
45
/// Seeding via [`rand::make_rng()`] or [`rand::rng()`] may be
46
/// faster:
47
/// ```
48
/// # use rand::rngs::StdRng;
49
/// let mut rng: StdRng = rand::make_rng();
50
/// # let _ = rand::Rng::next_u32(&mut rng);
51
/// ```
52
///
53
/// Any [`SeedableRng`] method may be used, but note that `seed_from_u64` is not
54
/// suitable where security is required. See also [Seeding RNGs] in the book.
55
///
56
/// ## Generation
57
///
58
/// The generator implements [`Rng`] and thus also [`RngExt`].
59
/// See also the [Random Values] chapter in the book.
60
///
61
/// [portable]: https://rust-random.github.io/book/crate-reprod.html
62
/// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
63
/// [unpredictable]: https://rust-random.github.io/book/guide-rngs.html#security
64
/// [Random Values]: https://rust-random.github.io/book/guide-values.html
65
/// [CSPRNG]: https://rust-random.github.io/book/guide-gen.html#cryptographically-secure-pseudo-random-number-generator
66
/// [chacha20]: https://crates.io/crates/chacha20
67
/// [rand issue]: https://github.com/rust-random/rand/issues/932
68
/// [`Rng`]: rand_core::Rng
69
/// [`RngExt`]: crate::RngExt
70
/// [`rand::make_rng()`]: crate::make_rng
71
/// [`rand::rng()`]: crate::rng
72
#[derive(Debug, PartialEq, Eq)]
73
pub struct StdRng(Rng);
74
75
impl TryRng for StdRng {
76
    type Error = Infallible;
77
78
    #[inline(always)]
79
0
    fn try_next_u32(&mut self) -> Result<u32, Infallible> {
80
0
        self.0.try_next_u32()
81
0
    }
82
83
    #[inline(always)]
84
0
    fn try_next_u64(&mut self) -> Result<u64, Infallible> {
85
0
        self.0.try_next_u64()
86
0
    }
87
88
    #[inline(always)]
89
0
    fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Infallible> {
90
0
        self.0.try_fill_bytes(dst)
91
0
    }
92
}
93
94
impl SeedableRng for StdRng {
95
    // Fix to 256 bits. Changing this is a breaking change!
96
    type Seed = [u8; 32];
97
98
    #[inline(always)]
99
0
    fn from_seed(seed: Self::Seed) -> Self {
100
0
        StdRng(Rng::from_seed(seed))
101
0
    }
102
}
103
104
impl TryCryptoRng for StdRng {}
105
106
#[cfg(test)]
107
mod test {
108
    use crate::rngs::StdRng;
109
    use crate::{Rng, RngExt, SeedableRng};
110
111
    #[test]
112
    fn test_stdrng_construction() {
113
        // Test value-stability of StdRng. This is expected to break any time
114
        // the algorithm is changed.
115
        #[rustfmt::skip]
116
        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
117
                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
118
119
        let target = [10719222850664546238, 14064965282130556830];
120
121
        let mut rng0 = StdRng::from_seed(seed);
122
123
        let x0 = rng0.next_u64();
124
125
        let mut rng1 = StdRng::from_rng(&mut rng0);
126
        let x1 = rng1.next_u64();
127
128
        assert_eq!([x0, x1], target);
129
    }
130
131
    #[test]
132
    fn test_chacha_true_values_1() {
133
        // Source: Strombergson 2013, Test Vectors for the Stream Cipher ChaCha
134
        // draft-strombergson-chacha-test-vectors-01
135
        // https://datatracker.ietf.org/doc/html/draft-strombergson-chacha-test-vectors-01
136
        // Converted to LE u128 form (four u128 to one block).
137
        // TC: all zero key and IV, rounds 12, 256-bit key
138
139
        let seed = [0u8; 32];
140
        let mut rng = StdRng::from_seed(seed);
141
142
        let mut results = [0u128; 8];
143
        rng.fill(&mut results);
144
        let expected = [
145
            0xd583265f12ce1f8153f955076a9af49b,
146
            0x5f15ae2ea589007e1474e049bbc32904,
147
            0x798cfaac3428e82cc0e37ad279f86405,
148
            0xbe2613412fe80b611969dea02c9f623a,
149
            0x3d17e08c3371fc86fe743e204188d50b,
150
            0xb489c04c21851515cccbbd19b7eb28c6,
151
            0x43c88c1b97b802c611f14ca1cd8d2542,
152
            0x1693e617b0a64427c0515190ca461ee9,
153
        ];
154
        assert_eq!(results, expected);
155
156
        assert_eq!(rng.0.get_word_pos(), 32);
157
    }
158
159
    #[test]
160
    fn test_chacha_true_values_2() {
161
        // Source: Strombergson 2013, Test Vectors for the Stream Cipher ChaCha
162
        // TC2: single bit set in key, all zero IV, rounds 12, 256-bit key
163
164
        let mut seed = [0u8; 32];
165
        seed[0] = 1;
166
        let mut rng = StdRng::from_seed(seed);
167
168
        let mut results = [0u128; 8];
169
        rng.fill(&mut results);
170
        let expected = [
171
            0x9a225cdf090f0eef6b0565d596e0512,
172
            0x10dd4d0bff1802930f5d5290278c2449,
173
            0xfefdfe067d7a109ee254a4d9392200a6,
174
            0xc029dc60c972179bf2f944a0eb0f21f0,
175
            0x2a37692ab05e660e2404c6cbc566730c,
176
            0xc8a72980b8c4c72a0978bb6fb279f97a,
177
            0xaf15ba8e302e43907dfcbb17c23b5154,
178
            0xa9177125baafe601560d10ef48eb5ac6,
179
        ];
180
        assert_eq!(results, expected);
181
182
        assert_eq!(rng.0.get_word_pos(), 32);
183
    }
184
185
    #[test]
186
    fn test_chacha_true_values_3() {
187
        // Source: Strombergson 2013, Test Vectors for the Stream Cipher ChaCha
188
        // TC3: all zero key, single bit set in IV, rounds 12, 256-bit key
189
190
        let seed = [0u8; 32];
191
        let mut rng = StdRng::from_seed(seed);
192
        rng.0.set_stream(1);
193
194
        let mut results = [0u128; 8];
195
        rng.fill(&mut results);
196
        let expected = [
197
            0x3de08d69eff7ba6d4b8c827bf8bdb864,
198
            0x6929e19be5ad36988f411457633fb3f8,
199
            0xa5995d1de898cb9efccf8ef3a053c946,
200
            0xf1d8f021fb3f31ee4b9450a9a8ffced,
201
            0x28886a59a2b923fe42c422f2a7b49d55,
202
            0x23c72a9150a17ca76e8963134fee2251,
203
            0x67b7d07029cb2037e802f6a024bf0bf,
204
            0x6fa2523bbd836d3a01c8137c82b91afc,
205
        ];
206
        assert_eq!(results, expected);
207
208
        assert_eq!(rng.0.get_word_pos(), 32);
209
    }
210
211
    #[test]
212
    fn test_chacha_true_values_8() {
213
        // Source: Strombergson 2013, Test Vectors for the Stream Cipher ChaCha
214
        // TC8: key: 'All your base are belong to us!', IV: IETF2013, rounds 12, 256-bit key
215
216
        #[rustfmt::skip]
217
        let seed = [
218
            0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78,
219
            0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35,
220
            0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb,
221
            0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d,
222
        ];
223
        let iv = [0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21];
224
        let mut rng = StdRng::from_seed(seed);
225
        rng.0.set_stream(u64::from_le_bytes(iv));
226
227
        let mut results = [0u128; 8];
228
        rng.fill(&mut results);
229
        let expected = [
230
            0x10c08b11dc3be7b4066dbc8427078214,
231
            0xc19c7e1f25aa8669e018a96c7876793c,
232
            0x207c8db0992e2d24b483ee160a9a74b2,
233
            0xabfb0f9db3b1613b28876c46bc802b09,
234
            0x5495b60d624f9e9b32dbebc16b114bd9,
235
            0x31d66e96ad465a970c3d47689b3d8e4a,
236
            0x3c11e5a1df7a04d8c7ead50a53ff2ae4,
237
            0x2ba4a57be08f1cac89d1f183b8e3f391,
238
        ];
239
        assert_eq!(results, expected);
240
241
        assert_eq!(rng.0.get_word_pos(), 32);
242
    }
243
244
    #[test]
245
    fn test_chacha_counter() {
246
        // Source: rand_chacha implementation
247
        // We test six blocks: counter=u32::MAX, four blocks from 2^32 (backends
248
        // which yield four blocks at a time may need to handle this specially)
249
        // and the first block after this wrap-logic completes.
250
        // Test: all zero key and IV, block set to u32::MAX, rounds 12, 256-bit key
251
252
        let seed = [0u8; 32];
253
        let mut rng = StdRng::from_seed(seed);
254
        let block = u32::MAX;
255
        let words_per_block = 16;
256
        rng.0.set_word_pos((block as u128) * words_per_block);
257
258
        let mut results = [0u128; 4 * 6];
259
        rng.fill(&mut results);
260
        let expected = [
261
            0xf106e2fcbb524248292ac9f150afa6d7,
262
            0x12032ef6c183b50a83a3309513dd017d,
263
            0x2c93ff300438eaed6c958a9aa1619382,
264
            0x74fc0624270ab858508377945edb52d0,
265
            0xe5f4f4a8b8810524264d8911dc537bcc,
266
            0x18a6a6cbdc1f823fb1231280056740af,
267
            0xabdae0a44b1f45edbccc83dcd3f8638a,
268
            0xad6b649f12f70de567cc39740dbb8a22,
269
            0x37512785327825dc30ecfaf37a38f5a0,
270
            0x5af852d2df0dc286c2dd19af39b54e39,
271
            0xb04dc185c27497ac9f4a4f6769d1b5d,
272
            0x816492be66439cecd2498c9865284377,
273
            0x724fe95e0b6cbb8a55b707c06166147f,
274
            0xe3e7cda19d92b5318024abb34aa31329,
275
            0x1a3594d7283c077017cd511144bf3db3,
276
            0x99ab26cf14f38b11d78e413bdce6424c,
277
            0x553deaed89d3bf630de05408c0f655e8,
278
            0x86c46a5676fef18f0dc0dff3ee16507c,
279
            0xd33d6cf5ade97b000b29e3ce614faf51,
280
            0x5b62dcc48c0fc60326afc5783c40d40c,
281
            0x44eedc777ed030f43d382d4921eba244,
282
            0xa2d66a5893ade34a0d17c706e8d89dba,
283
            0xd229d1f3a07526e47cabd035135012fd,
284
            0xefae0722059b654dea6945547e535052,
285
        ];
286
        assert_eq!(results, expected);
287
288
        assert_eq!(rng.0.get_word_pos(), (block as u128) * words_per_block + 96);
289
    }
290
}