Skip to content

Commit

Permalink
NewSeeded: rename new → try_new, add new_with_fallback
Browse files Browse the repository at this point in the history
Rename OsRng::new → try_new too for consitency
Add dependency on time crate
(Note: better to use chrono, but has no real equivalent to precise_time_ns().)
  • Loading branch information
dhardy committed Oct 23, 2017
1 parent c4eb96c commit d6f8ebf
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ i128_support = ["rand_core/i128_support"]

[dependencies]
libc = "0.2"
time = "0.1"
rand_core = { path = 'rand_core' }

[target.'cfg(target_os = "fuchsia")'.dependencies]
Expand Down
6 changes: 3 additions & 3 deletions benches/distributions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rand::distributions::*;

#[bench]
fn distr_baseline(b: &mut Bencher) {
let mut rng = XorShiftRng::new().unwrap();
let mut rng = XorShiftRng::try_new().unwrap();

b.iter(|| {
for _ in 0..::RAND_BENCH_N {
Expand All @@ -29,7 +29,7 @@ macro_rules! distr_range_int {
($fnn:ident, $ty:ty, $low:expr, $high:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = XorShiftRng::new().unwrap();
let mut rng = XorShiftRng::try_new().unwrap();
let distr = Range::new($low, $high);

b.iter(|| {
Expand All @@ -52,7 +52,7 @@ macro_rules! distr_float {
($fnn:ident, $distr:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = XorShiftRng::new().unwrap();
let mut rng = XorShiftRng::try_new().unwrap();
let distr = $distr;

b.iter(|| {
Expand Down
6 changes: 3 additions & 3 deletions benches/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ macro_rules! gen_bytes {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen::new().unwrap();
let mut rng = $gen::try_new().unwrap();
let mut buf = [0u8; BYTES_LEN];
b.iter(|| {
for _ in 0..RAND_BENCH_N {
Expand All @@ -41,7 +41,7 @@ macro_rules! gen_usize {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen::new().unwrap();
let mut rng = $gen::try_new().unwrap();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(usize::rand(&mut rng, Default));
Expand All @@ -63,7 +63,7 @@ macro_rules! init_gen {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = XorShiftRng::new().unwrap();
let mut rng = XorShiftRng::try_new().unwrap();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box($gen::from_rng(&mut rng).unwrap());
Expand Down
4 changes: 2 additions & 2 deletions benches/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rand::sequences::{sample, Shuffle};

#[bench]
fn misc_shuffle_100(b: &mut Bencher) {
let mut rng = XorShiftRng::new().unwrap();
let mut rng = XorShiftRng::try_new().unwrap();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
x.shuffle(&mut rng);
Expand All @@ -20,7 +20,7 @@ fn misc_shuffle_100(b: &mut Bencher) {

#[bench]
fn misc_sample_10_of_100(b: &mut Bencher) {
let mut rng = XorShiftRng::new().unwrap();
let mut rng = XorShiftRng::try_new().unwrap();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample(&mut rng, x, 10));
Expand Down
57 changes: 57 additions & 0 deletions src/clock_rng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A not-very-random number generator using the system clock.

use {Rng, Error};
use rand_core::impls;
use time::precise_time_ns;

/// Clock-based `Rng`. Not very random.
pub struct ClockRng {
high: Option<u32>,
}

impl ClockRng {
/// Create a `ClockRng` (very low cost)
pub fn new() -> ClockRng {
ClockRng { high: None }
}
}

impl Rng for ClockRng {
fn next_u32(&mut self) -> u32 {
// We want to use both parts of precise_time_ns(), low part first
if let Some(high) = self.high.take() {
high
} else {
let ns = precise_time_ns();
self.high = Some((ns >> 32) as u32);
ns as u32
}
}

fn next_u64(&mut self) -> u64 {
precise_time_ns()
}

#[cfg(feature = "i128_support")]
fn next_u128(&mut self) -> u128 {
impls::next_u128_via_u64(self)
}

fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u64(self, dest)
}

fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Ok(self.fill_bytes(dest))
}
}
36 changes: 32 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@
extern crate core;

extern crate rand_core;
extern crate time;

pub use rand_core::{Rng, CryptoRng, SeedFromRng, SeedableRng, Error, ErrorKind};

Expand All @@ -269,6 +270,10 @@ pub use thread_local::{ThreadRng, thread_rng, random, random_with};
use prng::IsaacWordRng;
use distributions::range::Range;

// TODO: should we export this?
#[cfg(feature="std")] // not needed otherwise
mod clock_rng;

pub mod distributions;
pub mod iter;
pub mod mock;
Expand All @@ -294,14 +299,37 @@ mod thread_local;
#[cfg(feature="std")]
pub trait NewSeeded: Sized {
/// Creates a new instance, automatically seeded via `OsRng`.
fn new() -> Result<Self, Error>;
fn try_new() -> Result<Self, Error>;

/// Creates a new instance. If possible, this will just use `try_new` to
/// get entropy from `OsRng`; if not, it will use the system clock for
/// entropy.
///
/// Do not use this method for cryptography or anything requiring secure
/// random numbers.
///
/// This method can in theory panic, depending on the RNG being created,
/// but normally it shouldn't (SeedFromRng::from_rng is allowed to return
/// an error, but this would normally only happen if the source RNG errors;
/// the one used here does not).
fn new_with_fallback() -> Self;
}

#[cfg(feature="std")]
impl<R: SeedFromRng> NewSeeded for R {
fn new() -> Result<Self, Error> {
let mut r = OsRng::new()?;
Self::from_rng(&mut r)
fn try_new() -> Result<Self, Error> {
let mut src = OsRng::try_new()?;
Self::from_rng(&mut src)
}
fn new_with_fallback() -> Self {
match Self::try_new() {
Ok(result) => result,
Err(_) => {
let mut src = clock_rng::ClockRng::new();
Self::from_rng(&mut src).unwrap_or_else(|e|
panic!("Seeding from clock failed: {}", e))
}
}
}
}

Expand Down
24 changes: 12 additions & 12 deletions src/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ impl fmt::Debug for OsRng {

impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> Result<OsRng, Error> {
imp::OsRng::new().map(OsRng)
pub fn try_new() -> Result<OsRng, Error> {
imp::OsRng::try_new().map(OsRng)
}
}

Expand Down Expand Up @@ -211,7 +211,7 @@ mod imp {
}

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
if is_getrandom_available() {
return Ok(OsRng { inner: OsGetrandomRng });
}
Expand Down Expand Up @@ -253,7 +253,7 @@ mod imp {
}

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
Ok(OsRng)
}
pub fn try_fill(&mut self, v: &mut [u8]) -> Result<(), Error> {
Expand All @@ -278,7 +278,7 @@ mod imp {
pub struct OsRng;

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
Ok(OsRng)
}
pub fn try_fill(&mut self, v: &mut [u8]) -> Result<(), Error> {
Expand Down Expand Up @@ -311,7 +311,7 @@ mod imp {
pub struct OsRng;

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
Ok(OsRng)
}
pub fn try_fill(&mut self, v: &mut [u8]) -> Result<(), Error> {
Expand Down Expand Up @@ -342,7 +342,7 @@ mod imp {
}

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
let reader = File::open("rand:").unwrap();
let reader_rng = ReadRng(reader);

Expand All @@ -364,7 +364,7 @@ mod imp {
pub struct OsRng;

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
Ok(OsRng)
}
pub fn try_fill(&mut self, v: &mut [u8]) -> Result<(), Error> {
Expand Down Expand Up @@ -399,7 +399,7 @@ mod imp {
pub struct OsRng;

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
Ok(OsRng)
}
pub fn try_fill(&mut self, v: &mut [u8]) -> Result<(), Error> {
Expand Down Expand Up @@ -447,7 +447,7 @@ mod imp {
}

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
pub fn try_new() -> Result<OsRng, Error> {
let mut iface = NaClIRTRandom {
get_random_bytes: None,
};
Expand Down Expand Up @@ -494,7 +494,7 @@ mod test {

#[test]
fn test_os_rng() {
let mut r = OsRng::new().unwrap();
let mut r = OsRng::try_new().unwrap();

r.next_u32();
r.next_u64();
Expand All @@ -517,7 +517,7 @@ mod test {

// deschedule to attempt to interleave things as much
// as possible (XXX: is this a good test?)
let mut r = OsRng::new().unwrap();
let mut r = OsRng::try_new().unwrap();
thread::yield_now();
let mut v = [0u8; 1000];

Expand Down
3 changes: 2 additions & 1 deletion src/reseeding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ pub struct ReseedWithNew;
#[cfg(feature="std")]
impl<R: Rng + NewSeeded> Reseeder<R> for ReseedWithNew {
fn reseed(&mut self, rng: &mut R) {
match R::new() {
// TODO: should we use new_with_fallback instead?
match R::try_new() {
Ok(result) => *rng = result,
// TODO: should we ignore and continue without reseeding?
Err(e) => panic!("Reseeding failed: {:?}", e),
Expand Down
3 changes: 2 additions & 1 deletion src/thread_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ impl Rng for ThreadRng {

thread_local!(
static THREAD_RNG_KEY: Rc<RefCell<ReseedingStdRng>> = {
let r = match StdRng::new() {
// TODO: consider using new_with_fallback instead of try_new
let r = match StdRng::try_new() {
Ok(r) => r,
Err(e) => panic!("could not initialize thread_rng: {:?}", e)
};
Expand Down

0 comments on commit d6f8ebf

Please sign in to comment.