Skip to content

Add RDRAND feature #109

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

Closed
wants to merge 8 commits into from
Closed
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
@@ -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
@@ -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
17 changes: 9 additions & 8 deletions src/distributions/mod.rs
Original file line number Diff line number Diff line change
@@ -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> {
@@ -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
@@ -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,
6 changes: 3 additions & 3 deletions src/distributions/range.rs
Original file line number Diff line number Diff line change
@@ -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};
@@ -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
@@ -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 {
6 changes: 3 additions & 3 deletions src/isaac.rs
Original file line number Diff line number Diff line change
@@ -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};

53 changes: 44 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -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>;
@@ -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()
@@ -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() })
}
@@ -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(),
@@ -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() {
@@ -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>>,
@@ -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>> = {
@@ -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()
@@ -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
@@ -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()
@@ -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,
59 changes: 54 additions & 5 deletions src/os.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -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;

@@ -198,7 +199,7 @@ mod imp {
}
}

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

@@ -248,7 +249,7 @@ mod imp {
}
}

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

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

@@ -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;
4 changes: 2 additions & 2 deletions src/rand_impls.rs
Original file line number Diff line number Diff line change
@@ -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};

5 changes: 3 additions & 2 deletions src/read.rs
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/reseeding.rs
Original file line number Diff line number Diff line change
@@ -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};