mirror of
https://github.com/rust-lang/rust
synced 2024-09-15 22:50:55 +00:00
Auto merge of #31738 - seanmonstar:sys-rand, r=alexcrichton
This commit is contained in:
commit
d5e2e5fbbc
|
@ -62,6 +62,7 @@
|
|||
use io;
|
||||
use mem;
|
||||
use rc::Rc;
|
||||
use sys;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
use core_rand::IsaacRng as IsaacWordRng;
|
||||
|
@ -71,9 +72,7 @@
|
|||
pub use core_rand::{Rand, Rng, SeedableRng};
|
||||
pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng};
|
||||
pub use core_rand::reseeding;
|
||||
pub use rand::os::OsRng;
|
||||
|
||||
pub mod os;
|
||||
pub mod reader;
|
||||
|
||||
/// The standard RNG. This is designed to be efficient on the current
|
||||
|
@ -185,3 +184,95 @@ fn fill_bytes(&mut self, bytes: &mut [u8]) {
|
|||
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_str;
|
||||
pub mod pipe;
|
||||
pub mod process;
|
||||
pub mod rand;
|
||||
pub mod rwlock;
|
||||
pub mod stack_overflow;
|
||||
pub mod thread;
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Interfaces to the operating system provided random number
|
||||
//! generators.
|
||||
|
||||
pub use self::imp::OsRng;
|
||||
|
||||
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
|
||||
|
@ -125,17 +122,6 @@ fn is_getrandom_available() -> bool {
|
|||
target_arch = "powerpc64"))))]
|
||||
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 {
|
||||
inner: OsRngInner,
|
||||
}
|
||||
|
@ -189,17 +175,6 @@ mod imp {
|
|||
use sys::os::errno;
|
||||
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 {
|
||||
// dummy field to ensure that this struct cannot be constructed outside
|
||||
// of this module
|
||||
|
@ -246,17 +221,6 @@ mod imp {
|
|||
use rand::Rng;
|
||||
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 {
|
||||
// dummy field to ensure that this struct cannot be constructed outside
|
||||
// of this module
|
||||
|
@ -307,133 +271,3 @@ fn fill_bytes(&mut self, v: &mut [u8]) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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_str;
|
||||
pub mod pipe;
|
||||
pub mod process;
|
||||
pub mod rand;
|
||||
pub mod rwlock;
|
||||
pub mod stack_overflow;
|
||||
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…
Reference in a new issue