1 // Copyright 2018 Developers of the Rand project.
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.
9 //! Thread-local random number generator
11 use std
::cell
::UnsafeCell
;
12 use std
::ptr
::NonNull
;
15 use crate::rngs
::adapter
::ReseedingRng
;
16 use crate::rngs
::OsRng
;
17 use crate::{CryptoRng, Error, RngCore, SeedableRng}
;
19 // Rationale for using `UnsafeCell` in `ThreadRng`:
21 // Previously we used a `RefCell`, with an overhead of ~15%. There will only
22 // ever be one mutable reference to the interior of the `UnsafeCell`, because
23 // we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
24 // single thread (which is the definition of `ThreadRng`), there will only ever
25 // be one of these methods active at a time.
27 // A possible scenario where there could be multiple mutable references is if
28 // `ThreadRng` is used inside `next_u32` and co. But the implementation is
29 // completely under our control. We just have to ensure none of them use
30 // `ThreadRng` internally, which is nonsensical anyway. We should also never run
31 // `ThreadRng` in destructors of its implementation, which is also nonsensical.
34 // Number of generated bytes after which to reseed `ThreadRng`.
35 // According to benchmarks, reseeding has a noticable impact with thresholds
36 // of 32 kB and less. We choose 64 kB to avoid significant overhead.
37 const THREAD_RNG_RESEED_THRESHOLD
: u64 = 1024 * 64;
39 /// The type returned by [`thread_rng`], essentially just a reference to the
40 /// PRNG in thread-local memory.
42 /// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
43 /// As hinted by the name, the generator is thread-local. `ThreadRng` is a
44 /// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
46 /// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
47 /// the PRNG from fresh entropy every 64 kiB of random data.
48 /// [`OsRng`] is used to provide seed data.
50 /// Note that the reseeding is done as an extra precaution against side-channel
51 /// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
52 /// The PRNG algorithms used are assumed to be secure.
54 /// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
55 /// [`StdRng`]: crate::rngs::StdRng
56 #[derive(Copy, Clone, Debug)]
57 pub struct ThreadRng
{
58 // inner raw pointer implies type is neither Send nor Sync
59 rng
: NonNull
<ReseedingRng
<Core
, OsRng
>>,
63 static THREAD_RNG_KEY
: UnsafeCell
<ReseedingRng
<Core
, OsRng
>> = {
64 let r
= Core
::from_rng(OsRng
).unwrap_or_else(|err
|
65 panic
!("could not initialize thread_rng: {}", err
));
66 let rng
= ReseedingRng
::new(r
,
67 THREAD_RNG_RESEED_THRESHOLD
,
73 /// Retrieve the lazily-initialized thread-local random number generator,
74 /// seeded by the system. Intended to be used in method chaining style,
75 /// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
76 /// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making
77 /// `ThreadRng::default()` equivalent.
79 /// For more information see [`ThreadRng`].
80 pub fn thread_rng() -> ThreadRng
{
81 let raw
= THREAD_RNG_KEY
.with(|t
| t
.get());
82 let nn
= NonNull
::new(raw
).unwrap();
86 impl Default
for ThreadRng
{
87 fn default() -> ThreadRng
{
88 crate::prelude
::thread_rng()
92 impl RngCore
for ThreadRng
{
94 fn next_u32(&mut self) -> u32 {
95 unsafe { self.rng.as_mut().next_u32() }
99 fn next_u64(&mut self) -> u64 {
100 unsafe { self.rng.as_mut().next_u64() }
103 fn fill_bytes(&mut self, dest
: &mut [u8]) {
104 unsafe { self.rng.as_mut().fill_bytes(dest) }
107 fn try_fill_bytes(&mut self, dest
: &mut [u8]) -> Result
<(), Error
> {
108 unsafe { self.rng.as_mut().try_fill_bytes(dest) }
112 impl CryptoRng
for ThreadRng {}
118 fn test_thread_rng() {
120 let mut r
= crate::thread_rng();
122 assert_eq
!(r
.gen_range(0, 1), 0);