aboutsummaryrefslogtreecommitdiff
path: root/rand/src/rngs/thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rand/src/rngs/thread.rs')
-rw-r--r--rand/src/rngs/thread.rs91
1 files changed, 37 insertions, 54 deletions
diff --git a/rand/src/rngs/thread.rs b/rand/src/rngs/thread.rs
index 7977d85..2006f41 100644
--- a/rand/src/rngs/thread.rs
+++ b/rand/src/rngs/thread.rs
@@ -9,11 +9,12 @@
//! Thread-local random number generator
use std::cell::UnsafeCell;
+use std::ptr::NonNull;
-use {RngCore, CryptoRng, SeedableRng, Error};
-use rngs::adapter::ReseedingRng;
-use rngs::EntropyRng;
-use rand_hc::Hc128Core;
+use crate::{RngCore, CryptoRng, SeedableRng, Error};
+use crate::rngs::adapter::ReseedingRng;
+use crate::rngs::OsRng;
+use super::std::Core;
// Rationale for using `UnsafeCell` in `ThreadRng`:
//
@@ -28,61 +29,43 @@ use rand_hc::Hc128Core;
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
-//
-// The additional `Rc` is not strictly neccesary, and could be removed. For now
-// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.
-// Number of generated bytes after which to reseed `TreadRng`.
-//
-// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
-// We pick a treshold here that is large enough to not reduce the average
-// performance too much, but also small enough to not make reseeding something
-// that basically never happens.
-const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB
+// Number of generated bytes after which to reseed `ThreadRng`.
+// According to benchmarks, reseeding has a noticable impact with thresholds
+// of 32 kB and less. We choose 64 kB to avoid significant overhead.
+const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
-/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
-/// which is reseeded after generating 32 MiB of random data. A single instance
-/// is cached per thread and the returned `ThreadRng` is a reference to this
-/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
-/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
-/// as required.
+/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
+/// As hinted by the name, the generator is thread-local. `ThreadRng` is a
+/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
///
-/// Note that the reseeding is done as an extra precaution against entropy
-/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
-/// attacker would have to either determine most of the RNG's seed or internal
-/// state, or crack the algorithm used.
+/// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
+/// the PRNG from fresh entropy every 64 kiB of random data.
+/// [`OsRng`] is used to provide seed data.
///
-/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
-/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
-/// usage for better performance. This makes it similar to ISAAC, the algorithm
-/// used in `ThreadRng` before rand 0.5.
+/// Note that the reseeding is done as an extra precaution against side-channel
+/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
+/// The PRNG algorithms used are assumed to be secure.
///
-/// Cloning this handle just produces a new reference to the same thread-local
-/// generator.
-///
-/// [`thread_rng`]: ../fn.thread_rng.html
-/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
-/// [`StdRng`]: struct.StdRng.html
-/// [`EntropyRng`]: struct.EntropyRng.html
-/// [HC-128]: ../../rand_hc/struct.Hc128Rng.html
-#[derive(Clone, Debug)]
+/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
+/// [`StdRng`]: crate::rngs::StdRng
+#[derive(Copy, Clone, Debug)]
pub struct ThreadRng {
- // use of raw pointer implies type is neither Send nor Sync
- rng: *mut ReseedingRng<Hc128Core, EntropyRng>,
+ // inner raw pointer implies type is neither Send nor Sync
+ rng: NonNull<ReseedingRng<Core, OsRng>>,
}
thread_local!(
- static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>> = {
- let mut entropy_source = EntropyRng::new();
- let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
+ static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = {
+ let r = Core::from_rng(OsRng).unwrap_or_else(|err|
panic!("could not initialize thread_rng: {}", err));
let rng = ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD,
- entropy_source);
+ OsRng);
UnsafeCell::new(rng)
}
);
@@ -91,38 +74,38 @@ thread_local!(
/// seeded by the system. Intended to be used in method chaining style,
/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making
-/// `ThreadRng::default()` equivelent.
+/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
-///
-/// [`ThreadRng`]: rngs/struct.ThreadRng.html
pub fn thread_rng() -> ThreadRng {
- ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) }
+ let raw = THREAD_RNG_KEY.with(|t| t.get());
+ let nn = NonNull::new(raw).unwrap();
+ ThreadRng { rng: nn }
}
impl Default for ThreadRng {
fn default() -> ThreadRng {
- ::prelude::thread_rng()
+ crate::prelude::thread_rng()
}
}
impl RngCore for ThreadRng {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
- unsafe { (*self.rng).next_u32() }
+ unsafe { self.rng.as_mut().next_u32() }
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
- unsafe { (*self.rng).next_u64() }
+ unsafe { self.rng.as_mut().next_u64() }
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
- unsafe { (*self.rng).fill_bytes(dest) }
+ unsafe { self.rng.as_mut().fill_bytes(dest) }
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
- unsafe { (*self.rng).try_fill_bytes(dest) }
+ unsafe { self.rng.as_mut().try_fill_bytes(dest) }
}
}
@@ -133,8 +116,8 @@ impl CryptoRng for ThreadRng {}
mod test {
#[test]
fn test_thread_rng() {
- use Rng;
- let mut r = ::thread_rng();
+ use crate::Rng;
+ let mut r = crate::thread_rng();
r.gen::<i32>();
assert_eq!(r.gen_range(0, 1), 0);
}