From a8c833e7643313335c3e29d5517fb21c1eec2976 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Sat, 21 Oct 2017 18:23:39 -0700 Subject: [PATCH 1/3] Add test_weak_rng --- src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index cd856d1885b..17f7e7d5ea9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1042,7 +1042,8 @@ pub fn sample(rng: &mut R, iterable: I, amount: usize) -> Vec #[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 { inner: R } @@ -1286,4 +1287,13 @@ mod test { let string2 = r.gen_ascii_chars().take(100).collect::(); assert_eq!(string1, string2); } + + #[test] + fn test_weak_rng() { + let s = weak_rng().gen_iter::().take(256).collect::>(); + 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))); + } } From 807b14229835a0414d98bc2b16112e18ef07295f Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 23 Oct 2017 22:59:05 -0700 Subject: [PATCH 2/3] Generate weak_rng from thread_rng --- src/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 17f7e7d5ea9..fc2c1c9c7d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -891,13 +891,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. From 6d297d52284a429ad7318559823c23ef48d197e6 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 23 Oct 2017 22:58:51 -0700 Subject: [PATCH 3/3] Seed thread_rng with the current time if OsRng fails. Fixes #180. --- src/lib.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fc2c1c9c7d6..3c7d2cc5149 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; @@ -902,9 +903,9 @@ struct ThreadRngReseeder; impl reseeding::Reseeder 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()) } } } @@ -921,8 +922,9 @@ pub struct ThreadRng { /// generator, seeded by the system. Intended to be used in method /// chaining style, e.g. `thread_rng().gen::()`. /// -/// 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 @@ -933,7 +935,7 @@ pub fn thread_rng() -> ThreadRng { thread_local!(static THREAD_RNG_KEY: Rc> = { 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, @@ -944,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()