Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seed weak_rng with the current time if OsRng fails #181

Merged
merged 3 commits into from
Oct 27, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ use std::mem;
use std::io;
use std::rc::Rc;
use std::num::Wrapping as w;
use std::time;

pub use os::OsRng;

Expand Down Expand Up @@ -891,13 +892,9 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
/// seeded `Rng` for consistency over time you should pick one algorithm and
/// create the `Rng` yourself.
///
/// This will read randomness from the operating system to seed the
/// generator.
/// This will seed the generator with randomness from thread_rng.
pub fn weak_rng() -> XorShiftRng {
match OsRng::new() {
Ok(mut r) => r.gen(),
Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
}
thread_rng().gen()
}

/// Controls how the thread-local RNG is reseeded.
Expand All @@ -906,9 +903,9 @@ struct ThreadRngReseeder;

impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
fn reseed(&mut self, rng: &mut StdRng) {
*rng = match StdRng::new() {
Ok(r) => r,
Err(e) => panic!("could not reseed thread_rng: {}", e)
match StdRng::new() {
Ok(r) => *rng = r,
Err(_) => rng.reseed(&weak_seed())
}
}
}
Expand All @@ -925,8 +922,9 @@ pub struct ThreadRng {
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`.
///
/// The RNG provided will reseed itself from the operating system
/// after generating a certain amount of randomness.
/// After generating a certain amount of randomness, the RNG will reseed itself
/// from the operating system or, if the operating system RNG returns an error,
/// a seed based on the current system time.
///
/// The internal RNG used is platform and architecture dependent, even
/// if the operating system random number generator is rigged to give
Expand All @@ -937,7 +935,7 @@ pub fn thread_rng() -> ThreadRng {
thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = {
let r = match StdRng::new() {
Ok(r) => r,
Err(e) => panic!("could not initialize thread_rng: {}", e)
Err(_) => StdRng::from_seed(&weak_seed())
};
let rng = reseeding::ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD,
Expand All @@ -948,6 +946,14 @@ pub fn thread_rng() -> ThreadRng {
ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

fn weak_seed() -> [usize; 2] {
let now = time::SystemTime::now();
let unix_time = now.duration_since(time::UNIX_EPOCH).unwrap();
let seconds = unix_time.as_secs() as usize;
let nanoseconds = unix_time.subsec_nanos() as usize;
[seconds, nanoseconds]
}

impl Rng for ThreadRng {
fn next_u32(&mut self) -> u32 {
self.rng.borrow_mut().next_u32()
Expand Down Expand Up @@ -1042,7 +1048,8 @@ pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>

#[cfg(test)]
mod test {
use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample};
use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample,
weak_rng};
use std::iter::repeat;

pub struct MyRng<R> { inner: R }
Expand Down Expand Up @@ -1286,4 +1293,13 @@ mod test {
let string2 = r.gen_ascii_chars().take(100).collect::<String>();
assert_eq!(string1, string2);
}

#[test]
fn test_weak_rng() {
let s = weak_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
let mut ra: StdRng = SeedableRng::from_seed(&s[..]);
let mut rb: StdRng = SeedableRng::from_seed(&s[..]);
assert!(iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
}