Skip to content

Commit 81a5422

Browse files
authored
Merge pull request #181 from cpeterso/cpeterso-weak_rng-seed
Seed weak_rng with the current time if OsRng fails
2 parents 6fd1009 + 6d297d5 commit 81a5422

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

src/lib.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ use std::mem;
254254
use std::io;
255255
use std::rc::Rc;
256256
use std::num::Wrapping as w;
257+
use std::time;
257258

258259
pub use os::OsRng;
259260

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

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

907904
impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
908905
fn reseed(&mut self, rng: &mut StdRng) {
909-
*rng = match StdRng::new() {
910-
Ok(r) => r,
911-
Err(e) => panic!("could not reseed thread_rng: {}", e)
906+
match StdRng::new() {
907+
Ok(r) => *rng = r,
908+
Err(_) => rng.reseed(&weak_seed())
912909
}
913910
}
914911
}
@@ -925,8 +922,9 @@ pub struct ThreadRng {
925922
/// generator, seeded by the system. Intended to be used in method
926923
/// chaining style, e.g. `thread_rng().gen::<i32>()`.
927924
///
928-
/// The RNG provided will reseed itself from the operating system
929-
/// after generating a certain amount of randomness.
925+
/// After generating a certain amount of randomness, the RNG will reseed itself
926+
/// from the operating system or, if the operating system RNG returns an error,
927+
/// a seed based on the current system time.
930928
///
931929
/// The internal RNG used is platform and architecture dependent, even
932930
/// if the operating system random number generator is rigged to give
@@ -937,7 +935,7 @@ pub fn thread_rng() -> ThreadRng {
937935
thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = {
938936
let r = match StdRng::new() {
939937
Ok(r) => r,
940-
Err(e) => panic!("could not initialize thread_rng: {}", e)
938+
Err(_) => StdRng::from_seed(&weak_seed())
941939
};
942940
let rng = reseeding::ReseedingRng::new(r,
943941
THREAD_RNG_RESEED_THRESHOLD,
@@ -948,6 +946,14 @@ pub fn thread_rng() -> ThreadRng {
948946
ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
949947
}
950948

949+
fn weak_seed() -> [usize; 2] {
950+
let now = time::SystemTime::now();
951+
let unix_time = now.duration_since(time::UNIX_EPOCH).unwrap();
952+
let seconds = unix_time.as_secs() as usize;
953+
let nanoseconds = unix_time.subsec_nanos() as usize;
954+
[seconds, nanoseconds]
955+
}
956+
951957
impl Rng for ThreadRng {
952958
fn next_u32(&mut self) -> u32 {
953959
self.rng.borrow_mut().next_u32()
@@ -1042,7 +1048,8 @@ pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
10421048

10431049
#[cfg(test)]
10441050
mod test {
1045-
use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample};
1051+
use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample,
1052+
weak_rng};
10461053
use std::iter::repeat;
10471054

10481055
pub struct MyRng<R> { inner: R }
@@ -1286,4 +1293,13 @@ mod test {
12861293
let string2 = r.gen_ascii_chars().take(100).collect::<String>();
12871294
assert_eq!(string1, string2);
12881295
}
1296+
1297+
#[test]
1298+
fn test_weak_rng() {
1299+
let s = weak_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
1300+
let mut ra: StdRng = SeedableRng::from_seed(&s[..]);
1301+
let mut rb: StdRng = SeedableRng::from_seed(&s[..]);
1302+
assert!(iter_eq(ra.gen_ascii_chars().take(100),
1303+
rb.gen_ascii_chars().take(100)));
1304+
}
12891305
}

0 commit comments

Comments
 (0)