]> git.proxmox.com Git - cargo.git/blob - vendor/rand/src/rngs/thread.rs
New upstream version 0.47.0
[cargo.git] / vendor / rand / src / rngs / thread.rs
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 //! Thread-local random number generator
10
11 use std::cell::UnsafeCell;
12 use std::ptr::NonNull;
13
14 use super::std::Core;
15 use crate::rngs::adapter::ReseedingRng;
16 use crate::rngs::OsRng;
17 use crate::{CryptoRng, Error, RngCore, SeedableRng};
18
19 // Rationale for using `UnsafeCell` in `ThreadRng`:
20 //
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.
26 //
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.
32
33
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;
38
39 /// The type returned by [`thread_rng`], essentially just a reference to the
40 /// PRNG in thread-local memory.
41 ///
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`.
45 ///
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.
49 ///
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.
53 ///
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>>,
60 }
61
62 thread_local!(
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,
68 OsRng);
69 UnsafeCell::new(rng)
70 }
71 );
72
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.
78 ///
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();
83 ThreadRng { rng: nn }
84 }
85
86 impl Default for ThreadRng {
87 fn default() -> ThreadRng {
88 crate::prelude::thread_rng()
89 }
90 }
91
92 impl RngCore for ThreadRng {
93 #[inline(always)]
94 fn next_u32(&mut self) -> u32 {
95 unsafe { self.rng.as_mut().next_u32() }
96 }
97
98 #[inline(always)]
99 fn next_u64(&mut self) -> u64 {
100 unsafe { self.rng.as_mut().next_u64() }
101 }
102
103 fn fill_bytes(&mut self, dest: &mut [u8]) {
104 unsafe { self.rng.as_mut().fill_bytes(dest) }
105 }
106
107 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
108 unsafe { self.rng.as_mut().try_fill_bytes(dest) }
109 }
110 }
111
112 impl CryptoRng for ThreadRng {}
113
114
115 #[cfg(test)]
116 mod test {
117 #[test]
118 fn test_thread_rng() {
119 use crate::Rng;
120 let mut r = crate::thread_rng();
121 r.gen::<i32>();
122 assert_eq!(r.gen_range(0, 1), 0);
123 }
124 }