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

Add RDRAND feature #109

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
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
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ Random number generators and other randomness functionality.
keywords = ["random", "rng"]

[dependencies]
libc = "0.2"
libc = { version = "0.2", optional = true }
core_io = { version = "0.1", optional = true } # enable use of read module on not(std)

[features]
default = ["std"]
std = ["libc"]
box = [] # enable use of Box on not(std), requires alloc crate and feature
vec = [] # enable use of Vec on not(std), requires collections crate and feature
rdrand = [] # with not(std), requires core_io

[dev-dependencies]
log = "0.3.0"
2 changes: 1 addition & 1 deletion src/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

//! The ChaCha random number generator.

use std::num::Wrapping as w;
use core::num::Wrapping as w;
use {Rng, SeedableRng, Rand, w32};

const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
Expand Down
17 changes: 9 additions & 8 deletions src/distributions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.

use std::marker;
use core::marker;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;
#[cfg(feature="std")] pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
#[cfg(feature="std")] pub use self::normal::{Normal, LogNormal};
#[cfg(feature="std")] pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;
#[cfg(feature="std")] pub mod gamma;
#[cfg(feature="std")] pub mod normal;
#[cfg(feature="std")] pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
Expand Down Expand Up @@ -201,7 +201,7 @@ impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
}
}

mod ziggurat_tables;
#[cfg(feature="std")] mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
Expand All @@ -218,6 +218,7 @@ mod ziggurat_tables;

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[cfg(feature="std")]
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(
rng: &mut R,
Expand Down
6 changes: 3 additions & 3 deletions src/distributions/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

// this is surprisingly complicated to be both generic & correct

use std::num::Wrapping as w;
use core::num::Wrapping as w;

use Rng;
use distributions::{Sample, IndependentSample};
Expand Down Expand Up @@ -98,7 +98,7 @@ macro_rules! integer_impl {

fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
let range = (w(high as $unsigned) - w(low as $unsigned)).0;
let unsigned_max: $unsigned = ::std::$unsigned::MAX;
let unsigned_max: $unsigned = ::core::$unsigned::MAX;

// this is the largest number that fits into $unsigned
// that `range` divides evenly, so, if we've sampled
Expand Down Expand Up @@ -185,7 +185,7 @@ mod tests {
$(
let v: &[($ty, $ty)] = &[(0, 10),
(10, 127),
(::std::$ty::MIN, ::std::$ty::MAX)];
(::core::$ty::MIN, ::core::$ty::MAX)];
for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high);
for _ in 0..1000 {
Expand Down
6 changes: 3 additions & 3 deletions src/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

#![allow(non_camel_case_types)]

use std::slice;
use std::iter::repeat;
use std::num::Wrapping as w;
use core::slice;
use core::iter::repeat;
use core::num::Wrapping as w;

use {Rng, SeedableRng, Rand, w32, w64};

Expand Down
53 changes: 44 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,31 @@
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/rand/")]

#![cfg_attr(not(feature="std"),no_std)]
#![cfg_attr(all(feature="box",not(feature="std")),feature(alloc))]
#![cfg_attr(all(feature="vec",not(feature="std")),feature(collections))]
#![cfg_attr(feature="rdrand",feature(asm))]

#[cfg(test)] #[macro_use] extern crate log;

use std::cell::RefCell;
use std::marker;
use std::mem;
use std::io;
use std::rc::Rc;
use std::num::Wrapping as w;
#[cfg(feature="std")] extern crate std as core;
#[cfg(all(feature="core_io",not(feature="std")))] extern crate core_io as io;
#[cfg(all(feature="box",not(feature="std")))] extern crate alloc;
#[cfg(all(feature="vec",not(feature="std")))] extern crate collections;

#[cfg(all(not(feature="std"),feature="rdrand",not(feature="core_io")))]
use using::rdrand::feature::without::std::feature::requires::core_io::feature;

pub use os::OsRng;
#[cfg(all(feature="std",not(feature="rdrand")))] use core::cell::RefCell;
use core::marker;
use core::mem;
#[cfg(feature="std")] use std::io;
#[cfg(all(feature="std",not(feature="rdrand")))] use std::rc::Rc;
use core::num::Wrapping as w;
#[cfg(all(feature="box",not(feature="std")))] use alloc::boxed::Box;
#[cfg(all(feature="vec",not(feature="std")))] use collections::vec::Vec;

#[cfg(any(feature="std",feature="rdrand"))] pub use os::OsRng;

pub use isaac::{IsaacRng, Isaac64Rng};
pub use chacha::ChaChaRng;
Expand All @@ -268,8 +283,8 @@ pub mod isaac;
pub mod chacha;
pub mod reseeding;
mod rand_impls;
pub mod os;
pub mod read;
#[cfg(any(feature="std",feature="rdrand"))] pub mod os;
#[cfg(any(feature="std",feature="core_io"))] pub mod read;

#[allow(bad_style)]
type w64 = w<u64>;
Expand Down Expand Up @@ -576,6 +591,7 @@ impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng {
}
}

#[cfg(any(feature="box",feature="std"))]
impl<R: ?Sized> Rng for Box<R> where R: Rng {
fn next_u32(&mut self) -> u32 {
(**self).next_u32()
Expand Down Expand Up @@ -810,6 +826,7 @@ impl StdRng {
///
/// Reading the randomness from the OS may fail, and any error is
/// propagated via the `io::Result` return value.
#[cfg(any(feature="std",feature="rdrand"))]
pub fn new() -> io::Result<StdRng> {
OsRng::new().map(|mut r| StdRng { rng: r.gen() })
}
Expand Down Expand Up @@ -848,6 +865,7 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
///
/// This will read randomness from the operating system to seed the
/// generator.
#[cfg(any(feature="std",feature="rdrand"))]
pub fn weak_rng() -> XorShiftRng {
match OsRng::new() {
Ok(mut r) => r.gen(),
Expand All @@ -856,8 +874,10 @@ pub fn weak_rng() -> XorShiftRng {
}

/// Controls how the thread-local RNG is reseeded.
#[cfg(all(feature="std",not(feature="rdrand")))]
struct ThreadRngReseeder;

#[cfg(all(feature="std",not(feature="rdrand")))]
impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
fn reseed(&mut self, rng: &mut StdRng) {
*rng = match StdRng::new() {
Expand All @@ -866,10 +886,13 @@ impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
}
}
}
#[cfg(all(feature="std",not(feature="rdrand")))]
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768;
#[cfg(all(feature="std",not(feature="rdrand")))]
type ThreadRngInner = reseeding::ReseedingRng<StdRng, ThreadRngReseeder>;

/// The thread-local RNG.
#[cfg(all(feature="std",not(feature="rdrand")))]
#[derive(Clone)]
pub struct ThreadRng {
rng: Rc<RefCell<ThreadRngInner>>,
Expand All @@ -886,6 +909,7 @@ pub struct ThreadRng {
/// if the operating system random number generator is rigged to give
/// the same sequence always. If absolute consistency is required,
/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
#[cfg(all(feature="std",not(feature="rdrand")))]
pub fn thread_rng() -> ThreadRng {
// used to make space in TLS for a random number generator
thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = {
Expand All @@ -902,6 +926,7 @@ pub fn thread_rng() -> ThreadRng {
ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

#[cfg(all(feature="std",not(feature="rdrand")))]
impl Rng for ThreadRng {
fn next_u32(&mut self) -> u32 {
self.rng.borrow_mut().next_u32()
Expand All @@ -917,6 +942,14 @@ impl Rng for ThreadRng {
}
}

#[cfg(feature="rdrand")]
pub use os::OsRng as ThreadRng;

#[cfg(feature="rdrand")]
pub fn thread_rng() -> ThreadRng {
OsRng::new().unwrap()
}

/// Generates a random value using the thread-local random number generator.
///
/// `random()` can generate various types of random things, and so may require
Expand Down Expand Up @@ -959,6 +992,7 @@ impl Rng for ThreadRng {
/// *x = rng.gen();
/// }
/// ```
#[cfg(any(feature="std",feature="rdrand"))]
#[inline]
pub fn random<T: Rand>() -> T {
thread_rng().gen()
Expand All @@ -975,6 +1009,7 @@ pub fn random<T: Rand>() -> T {
/// let sample = sample(&mut rng, 1..100, 5);
/// println!("{:?}", sample);
/// ```
#[cfg(any(feature="vec",feature="std"))]
pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
where I: IntoIterator<Item=T>,
R: Rng,
Expand Down
59 changes: 54 additions & 5 deletions src/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
//! Interfaces to the operating system provided random number
//! generators.

use std::io;
#[cfg(not(feature="std"))] use io;
#[cfg(feature="std")] use std::io;
use Rng;

/// A random number generator that retrieves randomness straight from
Expand Down Expand Up @@ -41,7 +42,7 @@ impl Rng for OsRng {
}

#[cfg(all(unix, not(target_os = "ios"),
not(target_os = "nacl")))]
not(target_os = "nacl"), not(feature = "rdrand")))]
mod imp {
extern crate libc;

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

#[cfg(target_os = "ios")]
#[cfg(all(target_os = "ios", not(feature = "rdrand")))]
mod imp {
extern crate libc;

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

#[cfg(windows)]
#[cfg(all(windows, not(feature = "rdrand")))]
mod imp {
use std::io;
use std::mem;
Expand Down Expand Up @@ -339,7 +340,7 @@ mod imp {
}
}

#[cfg(target_os = "nacl")]
#[cfg(all(target_os = "nacl", not(feature = "rdrand")))]
mod imp {
extern crate libc;

Expand Down Expand Up @@ -417,6 +418,54 @@ mod imp {
}


#[cfg(feature = "rdrand")]
mod imp {
#[cfg(not(feature="std"))] use io;
#[cfg(feature="std")] use std::io;

use Rng;

pub struct OsRng;

impl OsRng {
pub fn new() -> io::Result<OsRng> {
Ok(OsRng)
}
}

impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
let ret;
let mut retry=10;
unsafe{asm!("
1:
rdrand $0
jc 2f
dec $1
jnz 1b
2:
":"=r"(ret),"=r"(retry):"1"(retry)::"volatile")};
if retry==0 { panic!("RDRAND failure") }
ret
}
#[cfg(target_arch="x86_64")]
fn next_u64(&mut self) -> u64 {
let ret;
let mut retry=10;
unsafe{asm!("
1:
rdrand $0
jc 2f
dec $1
jnz 1b
2:
":"=r"(ret),"=r"(retry):"1"(retry)::"volatile")};
if retry==0 { panic!("RDRAND failure") }
ret
}
}
}

#[cfg(test)]
mod test {
use std::sync::mpsc::channel;
Expand Down
4 changes: 2 additions & 2 deletions src/rand_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

//! The implementations of `Rand` for the built-in types.

use std::char;
use std::mem;
use core::char;
use core::mem;

use {Rand,Rng};

Expand Down
5 changes: 3 additions & 2 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

//! A wrapper around any Read to treat it as an RNG.

use std::io::{self, Read};
use std::mem;
#[cfg(not(feature="std"))] use io::{self, Read};
#[cfg(feature="std")] use std::io::{self, Read};
use core::mem;
use Rng;

/// An RNG that reads random bytes straight from a `Read`. This will
Expand Down
2 changes: 1 addition & 1 deletion src/reseeding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes.

use std::default::Default;
use core::default::Default;

use {Rng, SeedableRng};

Expand Down