Merge pull request #6 from newpavlov/init

Crate implementation
This commit is contained in:
Diggory Hardy
2019-02-14 10:23:32 +00:00
committed by GitHub
22 changed files with 827 additions and 4 deletions
+18 -4
View File
@@ -1,9 +1,23 @@
[package]
name = "getrandom"
version = "0.0.0"
version = "0.1.0"
authors = ["The Rand Project Developers"]
license = "MIT/Apache-2.0"
edition = "2015"
license = "MIT OR Apache-2.0"
description = "A small cross-platform library to securely get random data (entropy)"
[dependencies]
[badges]
travis-ci = { repository = "rust-random/getrandom" }
appveyor = { repository = "rust-random/getrandom" }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] }
[target.'cfg(fuchsia)'.dependencies]
fuchsia-cprng = "0.1"
[target.wasm32-unknown-unknown.dependencies]
wasm-bindgen = { version = "0.2.12", optional = true }
stdweb = { version = "0.4", optional = true }
+24
View File
@@ -0,0 +1,24 @@
#![feature(test)]
extern crate test;
extern crate getrandom;
#[bench]
fn bench_64(b: &mut test::Bencher) {
let mut buf = [0u8; 64];
b.iter(|| {
getrandom::getrandom(&mut buf[..]).unwrap();
test::black_box(&buf);
});
b.bytes = buf.len() as u64;
}
#[bench]
fn bench_65536(b: &mut test::Bencher) {
let mut buf = [0u8; 65536];
b.iter(|| {
getrandom::getrandom(&mut buf[..]).unwrap();
test::black_box(&buf);
});
b.bytes = buf.len() as u64;
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use error::Error;
extern "C" {
fn cloudabi_sys_random_get(buf: *mut u8, len: usize) -> u16;
}
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let errno = unsafe { cloudabi_sys_random_get(dest.as_ptr(), dest.len()) };
if errno == 0 {
Ok(())
} else {
Err(Error(unsafe {
NonZeroU32::new_unchecked(errno as u32)
}))
}
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for DragonFly / Haiku
use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_FILE.with(|f| {
use_init(f,
|| File::open("/dev/random").map_err(From::from),
|f| f.read_exact(dest).map_err(From::from),
)
})
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A dummy implementation for unsupported targets which always returns
//! `Err(UNAVAILABLE_ERROR)`
use super::UNAVAILABLE_ERROR;
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
Err(UNAVAILABLE_ERROR)
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for Emscripten
use super::Error;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use super::utils::use_init;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
// `Crypto.getRandomValues` documents `dest` should be at most 65536
// bytes. `crypto.randomBytes` documents: "To minimize threadpool
// task length variation, partition large randomBytes requests when
// doing so as part of fulfilling a client request.
RNG_FILE.with(|f| {
use_init(f, || File::open("/dev/random").map_err(From::from), |f| {
for chunk in dest.chunks_mut(65536) {
f.read_exact(chunk)?;
}
Ok(())
})
})
}
+67
View File
@@ -0,0 +1,67 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::num::NonZeroU32;
use core::convert::From;
use core::fmt;
#[cfg(not(target_env = "sgx"))]
use std::{io, error};
pub const UNKNOWN_ERROR: Error = Error(unsafe {
NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
});
pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
});
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Error(NonZeroU32);
impl Error {
pub fn code(&self) -> NonZeroU32 {
self.0
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
code => write!(f, "Getrandom Error: {}", code.0.get()),
}
}
}
#[cfg(not(target_env = "sgx"))]
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
err.raw_os_error()
.and_then(|code| NonZeroU32::new(code as u32))
.map(|code| Error(code))
// in practice this should never happen
.unwrap_or(UNKNOWN_ERROR)
}
}
#[cfg(not(target_env = "sgx"))]
impl Into<io::Error> for Error {
fn into(self) -> io::Error {
match self {
UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
"getrandom error: unknown"),
UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
"getrandom error: entropy source is unavailable"),
code => io::Error::from_raw_os_error(code.0.get() as i32),
}
}
}
#[cfg(not(target_env = "sgx"))]
impl error::Error for Error { }
+32
View File
@@ -0,0 +1,32 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for FreeBSD
extern crate libc;
use super::Error;
use core::ptr;
use std::io;
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let mib = [libc::CTL_KERN, libc::KERN_ARND];
// kern.arandom permits a maximum buffer size of 256 bytes
for chunk in dest.chunks_mut(256) {
let mut len = chunk.len();
let ret = unsafe {
libc::sysctl(
mib.as_ptr(), mib.len() as libc::c_uint,
chunk.as_mut_ptr() as *mut _, &mut len, ptr::null(), 0,
)
};
if ret == -1 || len != chunk.len() {
return Err(io::Error::last_os_error().into());
}
}
Ok(())
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for Fuchsia Zircon
extern crate fuchsia_cprng;
use super::Error;
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
fuchsia_cprng::cprng_draw(dest);
Ok(())
}
+95
View File
@@ -5,3 +5,98 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![no_std]
#[cfg(not(target_env = "sgx"))]
#[macro_use] extern crate std;
#[cfg(any(
target_os = "android",
target_os = "netbsd",
target_os = "solaris",
target_os = "redox",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "linux",
))]
mod utils;
mod error;
pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR};
macro_rules! mod_use {
($cond:meta, $module:ident) => {
#[$cond]
mod $module;
#[$cond]
pub use $module::getrandom;
}
}
mod_use!(cfg(target_os = "android"), linux_android);
mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig);
mod_use!(cfg(target_os = "cloudabi"), cloudabi);
mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku);
mod_use!(cfg(target_os = "emscripten"), emscripten);
mod_use!(cfg(target_os = "freebsd"), freebsd);
mod_use!(cfg(target_os = "fuchsia"), fuchsia);
mod_use!(cfg(target_os = "haiku"), dragonfly_haiku);
mod_use!(cfg(target_os = "ios"), macos);
mod_use!(cfg(target_os = "linux"), linux_android);
mod_use!(cfg(target_os = "macos"), macos);
mod_use!(cfg(target_os = "netbsd"), netbsd);
mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig);
mod_use!(cfg(target_os = "redox"), redox);
mod_use!(cfg(target_os = "solaris"), solaris);
mod_use!(cfg(windows), windows);
mod_use!(cfg(target_env = "sgx"), sgx);
mod_use!(
cfg(all(
target_arch = "wasm32",
not(target_os = "emscripten"),
feature = "wasm-bindgen"
)),
wasm32_bindgen
);
mod_use!(
cfg(all(
target_arch = "wasm32",
not(target_os = "emscripten"),
not(feature = "wasm-bindgen"),
feature = "stdweb",
)),
wasm32_stdweb
);
mod_use!(
cfg(not(any(
target_os = "android",
target_os = "bitrig",
target_os = "cloudabi",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "haiku",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_env = "sgx",
windows,
all(
target_arch = "wasm32",
any(
target_os = "emscripten",
feature = "wasm-bindgen",
feature = "stdweb",
),
),
))),
dummy
);
+82
View File
@@ -0,0 +1,82 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for Linux / Android
extern crate libc;
use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io;
use std::io::Read;
use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
static RNG_INIT: AtomicBool = ATOMIC_BOOL_INIT;
enum RngSource {
GetRandom,
Device(File),
}
thread_local!(
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);
fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
let ret = unsafe {
libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
};
if ret == -1 || ret != dest.len() as i64 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_SOURCE.with(|f| {
use_init(f,
|| {
let s = if is_getrandom_available() {
RngSource::GetRandom
} else {
// read one byte from "/dev/random" to ensure that
// OS RNG has initialized
if !RNG_INIT.load(Ordering::Relaxed) {
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
RNG_INIT.store(true, Ordering::Relaxed)
}
RngSource::Device(File::open("/dev/urandom")?)
};
Ok(s)
}, |f| {
match f {
RngSource::GetRandom => syscall_getrandom(dest),
RngSource::Device(f) => f.read_exact(dest),
}.map_err(From::from)
})
})
}
fn is_getrandom_available() -> bool {
use std::sync::{Once, ONCE_INIT};
static CHECKER: Once = ONCE_INIT;
static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
CHECKER.call_once(|| {
let mut buf: [u8; 0] = [];
let available = match syscall_getrandom(&mut buf) {
Ok(()) => true,
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
};
AVAILABLE.store(available, Ordering::Relaxed);
});
AVAILABLE.load(Ordering::Relaxed)
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for MacOS / iOS
use super::Error;
use std::io;
// TODO: check correctness
#[allow(non_upper_case_globals)]
const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
#[link(name = "Security", kind = "framework")]
extern {
fn SecRandomCopyBytes(
rnd: *const SecRandom, count: size_t, bytes: *mut u8,
) -> c_int;
}
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe {
SecRandomCopyBytes(
kSecRandomDefault,
dest.len() as size_t,
dest.as_mut_ptr(),
)
};
if ret == -1 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for NetBSD
use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
static RNG_INIT: AtomicBool = ATOMIC_BOOL_INIT;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_FILE.with(|f| {
use_init(f, || {
// read one byte from "/dev/random" to ensure that
// OS RNG has initialized
if !RNG_INIT.load(Ordering::Relaxed) {
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
RNG_INIT.store(true, Ordering::Relaxed)
}
File::open("/dev/urandom").map_err(From::from)
}, |f| f.read_exact(dest).map_err(From::from))
})
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for OpenBSD / Bitrig
extern crate libc;
use super::Error;
use std::io;
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe {
libc::getentropy(
chunk.as_mut_ptr() as *mut libc::c_void,
chunk.len()
)
};
if ret == -1 {
return Err(io::Error::last_os_error().into());
}
}
Ok(())
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for Redox
use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_FILE.with(|f| {
use_init(f,
|| File::open("rand:").map_err(From::from),
|f| f.read_exact(dest).map_err(From::from),
)
}).map_err(From::from)
}
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for SGX using RDRAND instruction
use super::{Error, UNKNOWN_ERROR};
use core::{mem, ptr};
use core::arch::x86_64::_rdrand64_step;
#[cfg(not(target_feature = "rdrand"))]
compile_error!("enable rdrand target feature!");
const RETRY_LIMIT: usize = 32;
fn get_rand_u64() -> Result<u64, Error> {
for _ in 0..RETRY_LIMIT {
unsafe {
let mut el = mem::uninitialized();
if _rdrand64_step(&mut el) == 1 {
return Ok(el);
}
};
}
Err(UNKNOWN_ERROR)
}
pub fn getrandom(mut dest: &mut [u8]) -> Result<(), Error> {
while dest.len() >= 8 {
let (chunk, left) = {dest}.split_at_mut(8);
dest = left;
let r = get_rand_u64()?;
unsafe {
ptr::write_unaligned(chunk.as_mut_ptr() as *mut u64, r)
}
}
let n = dest.len();
if n != 0 {
let r = get_rand_u64()?;
let r: [u8; 8] = unsafe { mem::transmute(r) };
dest.copy_from_slice(&r[..n]);
}
Ok(())
}
+99
View File
@@ -0,0 +1,99 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for the Solaris family
//!
//! Read from `/dev/random`, with chunks of limited size (1040 bytes).
//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A.
//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less
//! secure. We choose to read from `/dev/random`.
//!
//! Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can
//! compile on both Solaris and on OpenSolaris derivatives, that do not have the
//! function, we do a direct syscall instead of calling a library function.
//!
//! We have no way to differentiate between Solaris, illumos, SmartOS, etc.
extern crate libc;
use super::Error;
use std::fs::File;
use std::io;
use std::io::Read;
use std::cell::RefCell;
use std::ops::DerefMut;
enum RngSource {
GetRandom,
Device(File),
}
thread_local!(
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);
fn syscall_getrandom(dest: &mut [u8]) -> Result<(), Error> {
// repalce with libc?
const SYS_GETRANDOM: libc::c_long = 143;
extern "C" {
fn syscall(number: libc::c_long, ...) -> libc::c_long;
}
let ret = unsafe {
syscall(SYS_GETRANDOM, dest.as_mut_ptr(), dest.len(), 0)
};
if ret == -1 || ret != dest.len() as i64 {
return Err(io::Error::last_os_error().from());
}
Ok(())
}
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
// The documentation says 1024 is the maximum for getrandom
// and 1040 for /dev/random.
RNG_SOURCE.with(|f| {
use_init(f,
|| {
let s = if is_getrandom_available() {
RngSource::GetRandom
} else {
RngSource::Device(File::open("/dev/random")?)
};
Ok(s)
}, |f| {
match f {
RngSource::GetRandom => for chunk in dest.chunks_mut(1024) {
syscall_getrandom(chunk)
},
RngSource::Device(f) => for chunk in dest.chunks_mut(1040) {
f.read_exact(dest).map_err(From::from)
},
}
})
}).map_err(|_| Error::Unknown)
}
fn is_getrandom_available() -> bool {
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use std::sync::{Once, ONCE_INIT};
static CHECKER: Once = ONCE_INIT;
static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
CHECKER.call_once(|| {
let mut buf: [u8; 0] = [];
let available = match syscall_getrandom(&mut buf) {
Ok(()) => true,
Err(ref err) if err.raw_os_error() == Some(libc::ENOSYS) => false,
Err(_) => true,
};
AVAILABLE.store(available, Ordering::Relaxed);
});
AVAILABLE.load(Ordering::Relaxed)
}
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::Error;
use core::cell::RefCell;
use core::ops::DerefMut;
/// If `f` contains `Some(T)` call `use_f` using contents of `f` as an argument,
/// otherwise initialize `f` value using `init_f`, store resulting value in `f`
/// and call `use_f`.
pub(crate) fn use_init<T, F, U>(f: &RefCell<Option<T>>, init_f: F, mut use_f: U)
-> Result<(), Error>
where F: FnOnce() -> Result<T, Error>, U: FnMut(&mut T) -> Result<(), Error>
{
let mut f = f.borrow_mut();
let f: &mut Option<T> = f.deref_mut();
match f {
None => *f = Some(init_f()?),
_ => (),
}
match f {
Some(f) => use_f(f),
None => unreachable!(),
}
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for WASM via wasm-bindgen
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for WASM via stdweb
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for Windows
extern crate winapi;
use self::winapi::shared::minwindef::ULONG;
use self::winapi::um::ntsecapi::RtlGenRandom;
use self::winapi::um::winnt::PVOID;
use std::io;
use super::Error;
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe {
RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG)
};
if ret == 0 { return Err(io::Error::last_os_error().into()); }
Ok(())
}
+55
View File
@@ -0,0 +1,55 @@
extern crate getrandom;
use getrandom::getrandom;
#[test]
fn test_diff() {
let mut v1 = [0u8; 1000];
getrandom(&mut v1).unwrap();
let mut v2 = [0u8; 1000];
getrandom(&mut v2).unwrap();
let mut n_diff_bits = 0;
for i in 0..v1.len() {
n_diff_bits += (v1[i] ^ v2[i]).count_ones();
}
// Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input.
assert!(n_diff_bits >= v1.len() as u32);
}
#[test]
fn test_huge() {
let mut huge = [0u8; 100_000];
getrandom(&mut huge).unwrap();
}
#[cfg(any(unix, windows, target_os="redox", target_os = "fuchsia"))]
#[test]
fn test_multithreading() {
use std::sync::mpsc::channel;
use std::thread;
let mut txs = vec!();
for _ in 0..20 {
let (tx, rx) = channel();
txs.push(tx);
thread::spawn(move|| {
// wait until all the tasks are ready to go.
rx.recv().unwrap();
let mut v = [0u8; 1000];
for _ in 0..100 {
getrandom(&mut v).unwrap();
thread::yield_now();
}
});
}
// start all the tasks
for tx in txs.iter() {
tx.send(()).unwrap();
}
}