11
11
use core:: cell:: UnsafeCell ;
12
12
use std:: rc:: Rc ;
13
13
use std:: thread_local;
14
+ use std:: fmt;
14
15
15
16
use super :: std:: Core ;
16
17
use crate :: rngs:: adapter:: ReseedingRng ;
@@ -39,31 +40,43 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
39
40
40
41
/// A reference to the thread-local generator
41
42
///
43
+ /// This type is a reference to a lazily-initialized thread-local generator.
42
44
/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
43
45
/// This handle is safe to use everywhere (including thread-local destructors),
44
46
/// though it is recommended not to use inside a fork handler.
45
47
/// The handle cannot be passed between threads (is not `Send` or `Sync`).
46
48
///
47
- /// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
48
- /// and is automatically seeded from [`OsRng`].
49
+ /// `ThreadRng` uses the same CSPRNG as [`StdRng`], ChaCha12. As with
50
+ /// [`StdRng`], the algorithm may be changed, subject to reasonable expectations
51
+ /// of security and performance.
49
52
///
50
- /// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
51
- /// the PRNG from fresh entropy every 64 kiB of random data as well as after a
52
- /// fork on Unix (though not quite immediately; see documentation of
53
- /// [`ReseedingRng`]).
54
- /// Note that the reseeding is done as an extra precaution against side-channel
55
- /// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
56
- /// The PRNG algorithms used are assumed to be secure.
53
+ /// `ThreadRng` is automatically seeded from [`OsRng`] with periodic reseeding
54
+ /// (every 64 kiB, as well as "soon" after a fork on Unix — see [`ReseedingRng`]
55
+ /// documentation for details).
56
+ ///
57
+ /// Security must be considered relative to a thread model and validation
58
+ /// requirements. `ThreadRng` attempts to meet basic security considerations
59
+ /// for producing unpredictable random numbers: use a CSPRNG, use a
60
+ /// recommended platform-specific seed ([`OsRng`]), and avoid
61
+ /// leaking internal secrets e.g. via [`Debug`] implementation or serialization.
62
+ /// Memory is not zeroized on drop.
57
63
///
58
64
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
59
65
/// [`StdRng`]: crate::rngs::StdRng
60
66
#[ cfg_attr( doc_cfg, doc( cfg( all( feature = "std" , feature = "std_rng" ) ) ) ) ]
61
- #[ derive( Clone , Debug ) ]
67
+ #[ derive( Clone ) ]
62
68
pub struct ThreadRng {
63
69
// Rc is explicitly !Send and !Sync
64
70
rng : Rc < UnsafeCell < ReseedingRng < Core , OsRng > > > ,
65
71
}
66
72
73
+ /// Debug implementation does not leak internal state
74
+ impl fmt:: Debug for ThreadRng {
75
+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
76
+ write ! ( fmt, "ThreadRng {{ .. }}" )
77
+ }
78
+ }
79
+
67
80
thread_local ! (
68
81
// We require Rc<..> to avoid premature freeing when thread_rng is used
69
82
// within thread-local destructors. See #968.
@@ -77,13 +90,23 @@ thread_local!(
77
90
}
78
91
) ;
79
92
80
- /// Retrieve the lazily-initialized thread-local random number generator,
81
- /// seeded by the system. Intended to be used in method chaining style,
82
- /// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
83
- /// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making
84
- /// `ThreadRng::default()` equivalent.
93
+ /// Access the thread-local generator
94
+ ///
95
+ /// Returns a reference to the local [`ThreadRng`], initializing the generator
96
+ /// on the first call on each thread.
85
97
///
86
- /// For more information see [`ThreadRng`].
98
+ /// Example usage:
99
+ /// ```
100
+ /// use rand::Rng;
101
+ ///
102
+ /// # fn main() {
103
+ /// // rand::random() may be used instead of rand::thread_rng().gen():
104
+ /// println!("A random boolean: {}", rand::random::<bool>());
105
+ ///
106
+ /// let mut rng = rand::thread_rng();
107
+ /// println!("A simulated die roll: {}", rng.gen_range(1..=6));
108
+ /// # }
109
+ /// ```
87
110
#[ cfg_attr( doc_cfg, doc( cfg( all( feature = "std" , feature = "std_rng" ) ) ) ) ]
88
111
pub fn thread_rng ( ) -> ThreadRng {
89
112
let rng = THREAD_RNG_KEY . with ( |t| t. clone ( ) ) ;
@@ -92,7 +115,7 @@ pub fn thread_rng() -> ThreadRng {
92
115
93
116
impl Default for ThreadRng {
94
117
fn default ( ) -> ThreadRng {
95
- crate :: prelude :: thread_rng ( )
118
+ thread_rng ( )
96
119
}
97
120
}
98
121
@@ -140,4 +163,11 @@ mod test {
140
163
r. gen :: < i32 > ( ) ;
141
164
assert_eq ! ( r. gen_range( 0 ..1 ) , 0 ) ;
142
165
}
166
+
167
+ #[ test]
168
+ fn test_debug_output ( ) {
169
+ // We don't care about the exact output here, but it must not include
170
+ // private CSPRNG state or the cache stored by BlockRng!
171
+ assert_eq ! ( std:: format!( "{:?}" , crate :: thread_rng( ) ) , "ThreadRng { .. }" ) ;
172
+ }
143
173
}
0 commit comments