std: restructure rand os code into sys modules
This commit is contained in:
parent
b54770c245
commit
34dfc3991d
5 changed files with 167 additions and 168 deletions
|
@ -62,6 +62,7 @@ use cell::RefCell;
|
||||||
use io;
|
use io;
|
||||||
use mem;
|
use mem;
|
||||||
use rc::Rc;
|
use rc::Rc;
|
||||||
|
use sys;
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
use core_rand::IsaacRng as IsaacWordRng;
|
use core_rand::IsaacRng as IsaacWordRng;
|
||||||
|
@ -71,9 +72,7 @@ use core_rand::Isaac64Rng as IsaacWordRng;
|
||||||
pub use core_rand::{Rand, Rng, SeedableRng};
|
pub use core_rand::{Rand, Rng, SeedableRng};
|
||||||
pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng};
|
pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng};
|
||||||
pub use core_rand::reseeding;
|
pub use core_rand::reseeding;
|
||||||
pub use rand::os::OsRng;
|
|
||||||
|
|
||||||
pub mod os;
|
|
||||||
pub mod reader;
|
pub mod reader;
|
||||||
|
|
||||||
/// The standard RNG. This is designed to be efficient on the current
|
/// The standard RNG. This is designed to be efficient on the current
|
||||||
|
@ -185,3 +184,95 @@ impl Rng for ThreadRng {
|
||||||
self.rng.borrow_mut().fill_bytes(bytes)
|
self.rng.borrow_mut().fill_bytes(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A random number generator that retrieves randomness straight from
|
||||||
|
/// the operating system. Platform sources:
|
||||||
|
///
|
||||||
|
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
||||||
|
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
|
||||||
|
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
||||||
|
/// service provider with the `PROV_RSA_FULL` type.
|
||||||
|
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
|
||||||
|
/// - OpenBSD: uses the `getentropy(2)` system call.
|
||||||
|
///
|
||||||
|
/// This does not block.
|
||||||
|
pub struct OsRng(sys::rand::OsRng);
|
||||||
|
|
||||||
|
impl OsRng {
|
||||||
|
/// Create a new `OsRng`.
|
||||||
|
pub fn new() -> io::Result<OsRng> {
|
||||||
|
sys::rand::OsRng::new().map(OsRng)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rng for OsRng {
|
||||||
|
#[inline]
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
self.0.next_u32()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
self.0.next_u64()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fill_bytes(&mut self, bytes: &mut [u8]) {
|
||||||
|
self.0.fill_bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use sync::mpsc::channel;
|
||||||
|
use rand::Rng;
|
||||||
|
use super::OsRng;
|
||||||
|
use thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_os_rng() {
|
||||||
|
let mut r = OsRng::new().unwrap();
|
||||||
|
|
||||||
|
r.next_u32();
|
||||||
|
r.next_u64();
|
||||||
|
|
||||||
|
let mut v = [0; 1000];
|
||||||
|
r.fill_bytes(&mut v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_os_rng_tasks() {
|
||||||
|
|
||||||
|
let mut txs = vec!();
|
||||||
|
for _ in 0..20 {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
txs.push(tx);
|
||||||
|
|
||||||
|
thread::spawn(move|| {
|
||||||
|
// wait until all the threads are ready to go.
|
||||||
|
rx.recv().unwrap();
|
||||||
|
|
||||||
|
// deschedule to attempt to interleave things as much
|
||||||
|
// as possible (XXX: is this a good test?)
|
||||||
|
let mut r = OsRng::new().unwrap();
|
||||||
|
thread::yield_now();
|
||||||
|
let mut v = [0; 1000];
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
r.next_u32();
|
||||||
|
thread::yield_now();
|
||||||
|
r.next_u64();
|
||||||
|
thread::yield_now();
|
||||||
|
r.fill_bytes(&mut v);
|
||||||
|
thread::yield_now();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// start all the threads
|
||||||
|
for tx in &txs {
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ pub mod os;
|
||||||
pub mod os_str;
|
pub mod os_str;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
pub mod rand;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
pub mod stack_overflow;
|
pub mod stack_overflow;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Interfaces to the operating system provided random number
|
|
||||||
//! generators.
|
|
||||||
|
|
||||||
pub use self::imp::OsRng;
|
pub use self::imp::OsRng;
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
|
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
|
||||||
|
@ -125,17 +122,6 @@ mod imp {
|
||||||
target_arch = "powerpc64"))))]
|
target_arch = "powerpc64"))))]
|
||||||
fn is_getrandom_available() -> bool { false }
|
fn is_getrandom_available() -> bool { false }
|
||||||
|
|
||||||
/// A random number generator that retrieves randomness straight from
|
|
||||||
/// the operating system. Platform sources:
|
|
||||||
///
|
|
||||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
|
||||||
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
|
|
||||||
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
|
||||||
/// service provider with the `PROV_RSA_FULL` type.
|
|
||||||
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
|
|
||||||
/// - OpenBSD: uses the `getentropy(2)` system call.
|
|
||||||
///
|
|
||||||
/// This does not block.
|
|
||||||
pub struct OsRng {
|
pub struct OsRng {
|
||||||
inner: OsRngInner,
|
inner: OsRngInner,
|
||||||
}
|
}
|
||||||
|
@ -189,17 +175,6 @@ mod imp {
|
||||||
use sys::os::errno;
|
use sys::os::errno;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
/// A random number generator that retrieves randomness straight from
|
|
||||||
/// the operating system. Platform sources:
|
|
||||||
///
|
|
||||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
|
||||||
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
|
|
||||||
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
|
||||||
/// service provider with the `PROV_RSA_FULL` type.
|
|
||||||
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
|
|
||||||
/// - OpenBSD: uses the `getentropy(2)` system call.
|
|
||||||
///
|
|
||||||
/// This does not block.
|
|
||||||
pub struct OsRng {
|
pub struct OsRng {
|
||||||
// dummy field to ensure that this struct cannot be constructed outside
|
// dummy field to ensure that this struct cannot be constructed outside
|
||||||
// of this module
|
// of this module
|
||||||
|
@ -246,17 +221,6 @@ mod imp {
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use libc::{c_int, size_t};
|
use libc::{c_int, size_t};
|
||||||
|
|
||||||
/// A random number generator that retrieves randomness straight from
|
|
||||||
/// the operating system. Platform sources:
|
|
||||||
///
|
|
||||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
|
||||||
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
|
|
||||||
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
|
||||||
/// service provider with the `PROV_RSA_FULL` type.
|
|
||||||
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
|
|
||||||
/// - OpenBSD: uses the `getentropy(2)` system call.
|
|
||||||
///
|
|
||||||
/// This does not block.
|
|
||||||
pub struct OsRng {
|
pub struct OsRng {
|
||||||
// dummy field to ensure that this struct cannot be constructed outside
|
// dummy field to ensure that this struct cannot be constructed outside
|
||||||
// of this module
|
// of this module
|
||||||
|
@ -307,133 +271,3 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
mod imp {
|
|
||||||
use io;
|
|
||||||
use mem;
|
|
||||||
use rand::Rng;
|
|
||||||
use sys::c;
|
|
||||||
|
|
||||||
/// A random number generator that retrieves randomness straight from
|
|
||||||
/// the operating system. Platform sources:
|
|
||||||
///
|
|
||||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
|
||||||
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
|
|
||||||
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
|
||||||
/// service provider with the `PROV_RSA_FULL` type.
|
|
||||||
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
|
|
||||||
/// - OpenBSD: uses the `getentropy(2)` system call.
|
|
||||||
///
|
|
||||||
/// This does not block.
|
|
||||||
pub struct OsRng {
|
|
||||||
hcryptprov: c::HCRYPTPROV
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OsRng {
|
|
||||||
/// Create a new `OsRng`.
|
|
||||||
pub fn new() -> io::Result<OsRng> {
|
|
||||||
let mut hcp = 0;
|
|
||||||
let ret = unsafe {
|
|
||||||
c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
|
|
||||||
c::PROV_RSA_FULL,
|
|
||||||
c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
|
|
||||||
};
|
|
||||||
|
|
||||||
if ret == 0 {
|
|
||||||
Err(io::Error::last_os_error())
|
|
||||||
} else {
|
|
||||||
Ok(OsRng { hcryptprov: hcp })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rng for OsRng {
|
|
||||||
fn next_u32(&mut self) -> u32 {
|
|
||||||
let mut v = [0; 4];
|
|
||||||
self.fill_bytes(&mut v);
|
|
||||||
unsafe { mem::transmute(v) }
|
|
||||||
}
|
|
||||||
fn next_u64(&mut self) -> u64 {
|
|
||||||
let mut v = [0; 8];
|
|
||||||
self.fill_bytes(&mut v);
|
|
||||||
unsafe { mem::transmute(v) }
|
|
||||||
}
|
|
||||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
|
||||||
let ret = unsafe {
|
|
||||||
c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
|
|
||||||
v.as_mut_ptr())
|
|
||||||
};
|
|
||||||
if ret == 0 {
|
|
||||||
panic!("couldn't generate random bytes: {}",
|
|
||||||
io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for OsRng {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let ret = unsafe {
|
|
||||||
c::CryptReleaseContext(self.hcryptprov, 0)
|
|
||||||
};
|
|
||||||
if ret == 0 {
|
|
||||||
panic!("couldn't release context: {}",
|
|
||||||
io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use sync::mpsc::channel;
|
|
||||||
use rand::Rng;
|
|
||||||
use super::OsRng;
|
|
||||||
use thread;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_os_rng() {
|
|
||||||
let mut r = OsRng::new().unwrap();
|
|
||||||
|
|
||||||
r.next_u32();
|
|
||||||
r.next_u64();
|
|
||||||
|
|
||||||
let mut v = [0; 1000];
|
|
||||||
r.fill_bytes(&mut v);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_os_rng_tasks() {
|
|
||||||
|
|
||||||
let mut txs = vec!();
|
|
||||||
for _ in 0..20 {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
txs.push(tx);
|
|
||||||
|
|
||||||
thread::spawn(move|| {
|
|
||||||
// wait until all the threads are ready to go.
|
|
||||||
rx.recv().unwrap();
|
|
||||||
|
|
||||||
// deschedule to attempt to interleave things as much
|
|
||||||
// as possible (XXX: is this a good test?)
|
|
||||||
let mut r = OsRng::new().unwrap();
|
|
||||||
thread::yield_now();
|
|
||||||
let mut v = [0; 1000];
|
|
||||||
|
|
||||||
for _ in 0..100 {
|
|
||||||
r.next_u32();
|
|
||||||
thread::yield_now();
|
|
||||||
r.next_u64();
|
|
||||||
thread::yield_now();
|
|
||||||
r.fill_bytes(&mut v);
|
|
||||||
thread::yield_now();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// start all the threads
|
|
||||||
for tx in &txs {
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,6 +33,7 @@ pub mod os;
|
||||||
pub mod os_str;
|
pub mod os_str;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
pub mod rand;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
pub mod stack_overflow;
|
pub mod stack_overflow;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
|
|
72
src/libstd/sys/windows/rand.rs
Normal file
72
src/libstd/sys/windows/rand.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2013-2015 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.
|
||||||
|
|
||||||
|
|
||||||
|
use io;
|
||||||
|
use mem;
|
||||||
|
use rand::Rng;
|
||||||
|
use sys::c;
|
||||||
|
|
||||||
|
pub struct OsRng {
|
||||||
|
hcryptprov: c::HCRYPTPROV
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OsRng {
|
||||||
|
/// Create a new `OsRng`.
|
||||||
|
pub fn new() -> io::Result<OsRng> {
|
||||||
|
let mut hcp = 0;
|
||||||
|
let ret = unsafe {
|
||||||
|
c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
|
||||||
|
c::PROV_RSA_FULL,
|
||||||
|
c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
|
||||||
|
};
|
||||||
|
|
||||||
|
if ret == 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(OsRng { hcryptprov: hcp })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rng for OsRng {
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
let mut v = [0; 4];
|
||||||
|
self.fill_bytes(&mut v);
|
||||||
|
unsafe { mem::transmute(v) }
|
||||||
|
}
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
let mut v = [0; 8];
|
||||||
|
self.fill_bytes(&mut v);
|
||||||
|
unsafe { mem::transmute(v) }
|
||||||
|
}
|
||||||
|
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||||
|
let ret = unsafe {
|
||||||
|
c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
|
||||||
|
v.as_mut_ptr())
|
||||||
|
};
|
||||||
|
if ret == 0 {
|
||||||
|
panic!("couldn't generate random bytes: {}",
|
||||||
|
io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for OsRng {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let ret = unsafe {
|
||||||
|
c::CryptReleaseContext(self.hcryptprov, 0)
|
||||||
|
};
|
||||||
|
if ret == 0 {
|
||||||
|
panic!("couldn't release context: {}",
|
||||||
|
io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue