Merge branch 'master' into https

This commit is contained in:
Gabriel Majeri 2018-01-09 08:35:22 +02:00
commit 2da42d488c
25 changed files with 3346 additions and 1007 deletions

View File

@ -1,7 +1,5 @@
language: rust language: rust
sudo: false sudo: false
before_script:
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
matrix: matrix:
include: include:
@ -11,16 +9,21 @@ matrix:
os: osx os: osx
- rust: beta - rust: beta
- rust: nightly - rust: nightly
- rust: nightly
before_script:
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
script: script:
- cargo test - cargo doc --no-deps --all-features
- cargo test --benches
- cargo test --features nightly - cargo test --features nightly
- cargo test --manifest-path rand-derive/Cargo.toml after_success:
- cargo doc --no-deps --features nightly - travis-cargo --only nightly doc-upload
script: script:
- cargo test - cargo test
- cargo test --manifest-path rand-derive/Cargo.toml - cargo test --manifest-path rand-derive/Cargo.toml
after_success:
- travis-cargo --only nightly doc-upload
env: env:
global: global:
secure: "BdDntVHSompN+Qxz5Rz45VI4ZqhD72r6aPl166FADlnkIwS6N6FLWdqs51O7G5CpoMXEDvyYrjmRMZe/GYLIG9cmqmn/wUrWPO+PauGiIuG/D2dmfuUNvSTRcIe7UQLXrfP3yyfZPgqsH6pSnNEVopquQKy3KjzqepgriOJtbyY=" secure: "BdDntVHSompN+Qxz5Rz45VI4ZqhD72r6aPl166FADlnkIwS6N6FLWdqs51O7G5CpoMXEDvyYrjmRMZe/GYLIG9cmqmn/wUrWPO+PauGiIuG/D2dmfuUNvSTRcIe7UQLXrfP3yyfZPgqsH6pSnNEVopquQKy3KjzqepgriOJtbyY="

265
CHANGELOG.md Normal file
View File

@ -0,0 +1,265 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [0.4.2] - 2018-01-05
### Changed
- Use winapi on Windows
- Update for Fuchsia OS
- Remove dev-dependency on `log`
## [0.4.1] - 2017-12-17
### Added
- `no_std` support
## [0.4.0-pre.0] - 2017-12-11
### Added
- `JitterRng` added as a high-quality alternative entropy source using the
system timer
- new `seq` module with `sample_iter`, `sample_slice`, etc.
- WASM support via dummy implementations (fail at run-time)
- Additional benchmarks, covering generators and new seq code
### Changed
- `thread_rng` uses `JitterRng` if seeding from system time fails
(slower but more secure than previous method)
### Deprecated
- `sample` function deprecated (replaced by `sample_iter`)
## [0.3.18] - 2017-11-06
### Changed
- `thread_rng` is seeded from the system time if `OsRng` fails
- `weak_rng` now uses `thread_rng` internally
## [0.3.17] - 2017-10-07
### Changed
- Fuchsia: Magenta was renamed Zircon
## [0.3.16] - 2017-07-27
### Added
- Implement Debug for mote non-public types
- implement `Rand` for (i|u)i128
- Support for Fuchsia
### Changed
- Add inline attribute to SampleRange::construct_range.
This improves the benchmark for sample in 11% and for shuffle in 16%.
- Use `RtlGenRandom` instead of `CryptGenRandom`
## [0.3.15] - 2016-11-26
### Added
- Add `Rng` trait method `choose_mut`
- Redox support
### Changed
- Use `arc4rand` for `OsRng` on FreeBSD.
- Use `arc4random(3)` for `OsRng` on OpenBSD.
### Fixed
- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows
## [0.3.14] - 2016-02-13
### Fixed
- Inline definitions from winapi/advapi32, wich decreases build times
## [0.3.13] - 2016-01-09
### Fixed
- Compatible with Rust 1.7.0-nightly (needed some extra type annotations)
## [0.3.12] - 2015-11-09
### Changed
- Replaced the methods in `next_f32` and `next_f64` with the technique described
Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more
uniform distribution.
- Depend on libc 0.2
### Fixed
- Fix iterator protocol issue in `rand::sample`
## [0.3.11] - 2015-08-31
### Added
- Implement `Rand` for arrays with n <= 32
## [0.3.10] - 2015-08-17
### Added
- Support for NaCl platforms
### Changed
- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box<R>` where `R: ?Sized + Rng`
## [0.3.9] - 2015-06-18
### Changed
- Use `winapi` for Windows API things
### Fixed
- Fixed test on stable/nightly
- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu
## [0.3.8] - 2015-04-23
### Changed
- `log` is a dev dependency
### Fixed
- Fix race condition of atomics in `is_getrandom_available`
## [0.3.7] - 2015-04-03
### Fixed
- Derive Copy/Clone changes
## [0.3.6] - 2015-04-02
### Changed
- Move to stable Rust!
## [0.3.5] - 2015-04-01
### Fixed
- Compatible with Rust master
## [0.3.4] - 2015-03-31
### Added
- Implement Clone for `Weighted`
### Fixed
- Compatible with Rust master
## [0.3.3] - 2015-03-26
### Fixed
- Fix compile on Windows
## [0.3.2] - 2015-03-26
## [0.3.1] - 2015-03-26
### Fixed
- Fix compile on Windows
## [0.3.0] - 2015-03-25
### Changed
- Update to use log version 0.3.x
## [0.2.1] - 2015-03-22
### Fixed
- Compatible with Rust master
- Fixed iOS compilation
## [0.2.0] - 2015-03-06
### Fixed
- Compatible with Rust master (move from `old_io` to `std::io`)
## [0.1.4] - 2015-03-04
### Fixed
- Compatible with Rust master (use wrapping ops)
## [0.1.3] - 2015-02-20
### Fixed
- Compatible with Rust master
### Removed
- Removed Copy inplementaions from RNGs
## [0.1.2] - 2015-02-03
### Added
- Imported functionality from `std::rand`, including:
- `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()`
- `ReaderRng`: A wrapper around any Reader to treat it as an RNG.
- Imported documentation from `std::rand`
- Imported tests from `std::rand`
## [0.1.1] - 2015-02-03
### Added
- Migrate to a cargo-compatible directory structure.
### Fixed
- Do not use entropy during `gen_weighted_bool(1)`
## [Rust 0.12.0] - 2014-10-09
### Added
- Impl Rand for tuples of arity 11 and 12
- Include ChaCha pseudorandom generator
- Add `next_f64` and `next_f32` to Rng
- Implement Clone for PRNGs
### Changed
- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a
runtime is removed from Rust).
### Fixed
- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by
informing the optimiser that indexing is never out-of-bounds.
### Removed
- Removed the Deprecated `choose_option`
## [Rust 0.11.0] - 2014-07-02
### Added
- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random`
- `Rng::gen_iter()` which will return an infinite stream of random values
- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters
### Changed
- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1
- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()`
- Rename OSRng to OsRng
- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
- The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
### Removed
- `Rng::gen_vec()` was removed. Previous behavior can be regained with
`rng.gen_iter().take(n).collect()`
- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with
`rng.gen_ascii_chars().take(n).collect()`
- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
- Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported.
- Remove a slew of old deprecated functions
## [Rust 0.10] - 2014-04-03
### Changed
- replace `Rng.shuffle's` functionality with `.shuffle_mut`
- bubble up IO errors when creating an OSRng
### Fixed
- Use `fill()` instead of `read()`
- Rewrite OsRng in Rust for windows
## [0.10-pre] - 2014-03-02
### Added
- Seperate `rand` out of the standard library

View File

@ -1,6 +1,6 @@
[package] [package]
name = "rand" name = "rand"
version = "0.3.17" version = "0.4.2"
authors = ["The Rust Project Developers"] authors = ["The Rust Project Developers"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
readme = "README.md" readme = "README.md"
@ -14,17 +14,22 @@ keywords = ["random", "rng"]
categories = ["algorithms"] categories = ["algorithms"]
[features] [features]
i128_support = [] default = ["std"]
nightly = ["i128_support"] nightly = ["i128_support"] # enables all features requiring nightly rust
[dependencies] std = ["libc"] # default feature; without this rand uses libcore
libc = "0.2" alloc = [] # enables Vec and Box support without std
[dev-dependencies] i128_support = [] # enables i128 and u128 support
log = "0.3.0"
[target.'cfg(unix)'.dependencies]
libc = { version = "0.2", optional = true }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"] }
[workspace] [workspace]
members = ["rand-derive"] members = ["rand-derive"]
[target.'cfg(target_os = "fuchsia")'.dependencies] [target.'cfg(target_os = "fuchsia")'.dependencies]
fuchsia-zircon = "^0.2.1" fuchsia-zircon = "0.3.2"

View File

@ -14,7 +14,7 @@ Add this to your `Cargo.toml`:
```toml ```toml
[dependencies] [dependencies]
rand = "0.3" rand = "0.4"
``` ```
and this to your crate root: and this to your crate root:
@ -23,6 +23,19 @@ and this to your crate root:
extern crate rand; extern crate rand;
``` ```
### Versions
The `rand` crate has been at version `0.3` since March 2015. If you wish to
avoid all breaking changes you may wish to stick with this version.
Version `0.4`was released in December 2017. It contains almost no breaking
changes since the `0.3` series, but nevertheless contains some significant
new code, including a new "external" entropy source (`JitterRng`) and `no_std`
support.
Version `0.5` is in development and contains significant performance
improvements for the ISAAC random number generators.
## Examples ## Examples
There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data. There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.
@ -50,13 +63,55 @@ let mut rng = rand::ChaChaRng::new_unseeded();
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>()) println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
``` ```
## Features
By default, `rand` is built with all stable features available. The following
optional features are available:
- `i128_support` enables support for generating `u128` and `i128` values
- `nightly` enables all unstable features (`i128_support`)
- `std` enabled by default; by setting "default-features = false" `no_std`
mode is activated; this removes features depending on `std` functionality:
- `OsRng` is entirely unavailable
- `JitterRng` code is still present, but a nanosecond timer must be
provided via `JitterRng::new_with_timer`
- Since no external entropy is available, it is not possible to create
generators with fresh seeds (user must provide entropy)
- `thread_rng`, `weak_rng` and `random` are all disabled
- exponential, normal and gamma type distributions are unavailable
since `exp` and `log` functions are not provided in `core`
- any code requiring `Vec` or `Box`
- `alloc` can be used instead of `std` to provide `Vec` and `Box`
## Testing
Unfortunately, `cargo test` does not test everything. The following tests are
recommended:
```
# Basic tests for rand and sub-crates
cargo test --all
# Test no_std support (build only since nearly all tests require std)
cargo build --all --no-default-features
# Test 128-bit support (requires nightly)
cargo test --all --features nightly
# Benchmarks (requires nightly)
cargo bench
# or just to test the benchmark code:
cargo test --benches
```
# `derive(Rand)` # `derive(Rand)`
You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]` You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
directive. To use this first add this to your Cargo.toml: directive. To use this first add this to your Cargo.toml:
```toml ```toml
rand = "0.3" rand = "0.4"
rand_derive = "0.3" rand_derive = "0.3"
``` ```

View File

@ -32,6 +32,7 @@ install:
build: false build: false
test_script: test_script:
- cargo test --benches
- cargo test - cargo test
- cargo test --features nightly - cargo test --features nightly
- cargo test --manifest-path rand-derive/Cargo.toml - cargo test --manifest-path rand-derive/Cargo.toml

View File

@ -9,52 +9,7 @@ mod distributions;
use std::mem::size_of; use std::mem::size_of;
use test::{black_box, Bencher}; use test::{black_box, Bencher};
use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng}; use rand::{StdRng, Rng};
use rand::{OsRng, sample, weak_rng};
#[bench]
fn rand_xorshift(b: &mut Bencher) {
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}
#[bench]
fn rand_isaac(b: &mut Bencher) {
let mut rng: IsaacRng = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}
#[bench]
fn rand_isaac64(b: &mut Bencher) {
let mut rng: Isaac64Rng = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}
#[bench]
fn rand_std(b: &mut Bencher) {
let mut rng = StdRng::new().unwrap();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}
#[bench] #[bench]
fn rand_f32(b: &mut Bencher) { fn rand_f32(b: &mut Bencher) {
@ -77,21 +32,3 @@ fn rand_f64(b: &mut Bencher) {
}); });
b.bytes = size_of::<f64>() as u64 * RAND_BENCH_N; b.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
} }
#[bench]
fn rand_shuffle_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
rng.shuffle(x);
})
}
#[bench]
fn rand_sample_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
sample(&mut rng, x, 10);
})
}

133
benches/generators.rs Normal file
View File

@ -0,0 +1,133 @@
#![feature(test)]
extern crate test;
extern crate rand;
const RAND_BENCH_N: u64 = 1000;
const BYTES_LEN: usize = 1024;
use std::mem::size_of;
use test::{black_box, Bencher};
use rand::{Rng, StdRng, OsRng, JitterRng};
use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
macro_rules! gen_bytes {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng: $gen = OsRng::new().unwrap().gen();
let mut buf = [0u8; BYTES_LEN];
b.iter(|| {
for _ in 0..RAND_BENCH_N {
rng.fill_bytes(&mut buf);
black_box(buf);
}
});
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
}
}
}
macro_rules! gen_bytes_new {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen::new().unwrap();
let mut buf = [0u8; BYTES_LEN];
b.iter(|| {
for _ in 0..RAND_BENCH_N {
rng.fill_bytes(&mut buf);
black_box(buf);
}
});
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
}
}
}
gen_bytes!(gen_bytes_xorshift, XorShiftRng);
gen_bytes!(gen_bytes_isaac, IsaacRng);
gen_bytes!(gen_bytes_isaac64, Isaac64Rng);
gen_bytes!(gen_bytes_chacha, ChaChaRng);
gen_bytes_new!(gen_bytes_std, StdRng);
gen_bytes_new!(gen_bytes_os, OsRng);
macro_rules! gen_uint {
($fnn:ident, $ty:ty, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng: $gen = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<$ty>());
}
});
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
}
}
}
macro_rules! gen_uint_new {
($fnn:ident, $ty:ty, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen::new().unwrap();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<$ty>());
}
});
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
}
}
}
gen_uint!(gen_u32_xorshift, u32, XorShiftRng);
gen_uint!(gen_u32_isaac, u32, IsaacRng);
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng);
gen_uint!(gen_u32_chacha, u32, ChaChaRng);
gen_uint_new!(gen_u32_std, u32, StdRng);
gen_uint_new!(gen_u32_os, u32, OsRng);
gen_uint!(gen_u64_xorshift, u64, XorShiftRng);
gen_uint!(gen_u64_isaac, u64, IsaacRng);
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng);
gen_uint!(gen_u64_chacha, u64, ChaChaRng);
gen_uint_new!(gen_u64_std, u64, StdRng);
gen_uint_new!(gen_u64_os, u64, OsRng);
#[bench]
fn gen_u64_jitter(b: &mut Bencher) {
let mut rng = JitterRng::new().unwrap();
b.iter(|| {
black_box(rng.gen::<u64>());
});
b.bytes = size_of::<u64>() as u64;
}
macro_rules! init_gen {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
b.iter(|| {
let r2: $gen = rng.gen();
black_box(r2);
});
}
}
}
init_gen!(init_xorshift, XorShiftRng);
init_gen!(init_isaac, IsaacRng);
init_gen!(init_isaac64, Isaac64Rng);
init_gen!(init_chacha, ChaChaRng);
#[bench]
fn init_jitter(b: &mut Bencher) {
b.iter(|| {
black_box(JitterRng::new().unwrap());
});
}

62
benches/misc.rs Normal file
View File

@ -0,0 +1,62 @@
#![feature(test)]
extern crate test;
extern crate rand;
use test::{black_box, Bencher};
use rand::{Rng, weak_rng};
use rand::seq::*;
#[bench]
fn misc_shuffle_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
rng.shuffle(x);
black_box(&x);
})
}
#[bench]
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
})
}
#[bench]
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample_slice(&mut rng, x, 10));
})
}
#[bench]
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &[usize] = &[1; 100];
b.iter(|| {
black_box(sample_slice_ref(&mut rng, x, 10));
})
}
macro_rules! sample_indices {
($name:ident, $amount:expr, $length:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let mut rng = weak_rng();
b.iter(|| {
black_box(sample_indices(&mut rng, $length, $amount));
})
}
}
}
sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);

View File

@ -20,4 +20,4 @@ quote = "0.3"
syn = "0.11" syn = "0.11"
[dev-dependencies] [dev-dependencies]
rand = { path = "..", version = "0.3" } rand = { path = "..", version = "0.4" }

View File

@ -17,20 +17,29 @@
//! internally. The `IndependentSample` trait is for generating values //! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state. //! that do not need to record state.
use std::marker; use core::marker;
use {Rng, Rand}; use {Rng, Rand};
pub use self::range::Range; pub use self::range::Range;
#[cfg(feature="std")]
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT}; pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
#[cfg(feature="std")]
pub use self::normal::{Normal, LogNormal}; pub use self::normal::{Normal, LogNormal};
#[cfg(feature="std")]
pub use self::exponential::Exp; pub use self::exponential::Exp;
pub mod range; pub mod range;
#[cfg(feature="std")]
pub mod gamma; pub mod gamma;
#[cfg(feature="std")]
pub mod normal; pub mod normal;
#[cfg(feature="std")]
pub mod exponential; pub mod exponential;
#[cfg(feature="std")]
mod ziggurat_tables;
/// Types that can be used to create a random instance of `Support`. /// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> { pub trait Sample<Support> {
/// Generate a random value of `Support`, using `rng` as the /// Generate a random value of `Support`, using `rng` as the
@ -124,7 +133,7 @@ impl<'a, T: Clone> WeightedChoice<'a, T> {
/// ///
/// Panics if: /// Panics if:
/// ///
/// - `v` is empty /// - `items` is empty
/// - the total weight is 0 /// - the total weight is 0
/// - the total weight is larger than a `u32` can contain. /// - the total weight is larger than a `u32` can contain.
pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> { pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
@ -203,8 +212,6 @@ impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
} }
} }
mod ziggurat_tables;
/// Sample a random number using the Ziggurat method (specifically the /// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are /// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper: /// directly from the paper:
@ -220,6 +227,7 @@ mod ziggurat_tables;
// the perf improvement (25-50%) is definitely worth the extra code // the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining. // size from force-inlining.
#[cfg(feature="std")]
#[inline(always)] #[inline(always)]
fn ziggurat<R: Rng, P, Z>( fn ziggurat<R: Rng, P, Z>(
rng: &mut R, rng: &mut R,
@ -271,8 +279,8 @@ fn ziggurat<R: Rng, P, Z>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use {Rng, Rand}; use {Rng, Rand};
use impls;
use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample}; use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
@ -293,6 +301,10 @@ mod tests {
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
self.next_u32() as u64 self.next_u32() as u64
} }
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u32(self, dest)
}
} }
#[test] #[test]

View File

@ -12,7 +12,7 @@
// this is surprisingly complicated to be both generic & correct // this is surprisingly complicated to be both generic & correct
use std::num::Wrapping as w; use core::num::Wrapping as w;
use Rng; use Rng;
use distributions::{Sample, IndependentSample}; use distributions::{Sample, IndependentSample};
@ -99,7 +99,7 @@ macro_rules! integer_impl {
#[inline] #[inline]
fn construct_range(low: $ty, high: $ty) -> Range<$ty> { fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
let range = (w(high as $unsigned) - w(low as $unsigned)).0; 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 // this is the largest number that fits into $unsigned
// that `range` divides evenly, so, if we've sampled // that `range` divides evenly, so, if we've sampled
@ -136,11 +136,15 @@ integer_impl! { i8, u8 }
integer_impl! { i16, u16 } integer_impl! { i16, u16 }
integer_impl! { i32, u32 } integer_impl! { i32, u32 }
integer_impl! { i64, u64 } integer_impl! { i64, u64 }
#[cfg(feature = "i128_support")]
integer_impl! { i128, u128 }
integer_impl! { isize, usize } integer_impl! { isize, usize }
integer_impl! { u8, u8 } integer_impl! { u8, u8 }
integer_impl! { u16, u16 } integer_impl! { u16, u16 }
integer_impl! { u32, u32 } integer_impl! { u32, u32 }
integer_impl! { u64, u64 } integer_impl! { u64, u64 }
#[cfg(feature = "i128_support")]
integer_impl! { u128, u128 }
integer_impl! { usize, usize } integer_impl! { usize, usize }
macro_rules! float_impl { macro_rules! float_impl {
@ -187,7 +191,7 @@ mod tests {
$( $(
let v: &[($ty, $ty)] = &[(0, 10), let v: &[($ty, $ty)] = &[(0, 10),
(10, 127), (10, 127),
(::std::$ty::MIN, ::std::$ty::MAX)]; (::core::$ty::MIN, ::core::$ty::MAX)];
for &(low, high) in v.iter() { for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high); let mut sampler: Range<$ty> = Range::new(low, high);
for _ in 0..1000 { for _ in 0..1000 {
@ -200,8 +204,12 @@ mod tests {
)* )*
}} }}
} }
#[cfg(not(feature = "i128_support"))]
t!(i8, i16, i32, i64, isize, t!(i8, i16, i32, i64, isize,
u8, u16, u32, u64, usize) u8, u16, u32, u64, usize);
#[cfg(feature = "i128_support")]
t!(i8, i16, i32, i64, i128, isize,
u8, u16, u32, u64, u128, usize);
} }
#[test] #[test]

170
src/impls.rs Normal file
View File

@ -0,0 +1,170 @@
// Copyright 2013-2017 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.
//! Helper functions for implementing `Rng` functions.
//!
//! For cross-platform reproducibility, these functions all use Little Endian:
//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
//!
//! Byte-swapping (like the std `to_le` functions) is only needed to convert
//! to/from byte sequences, and since its purpose is reproducibility,
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
// TODO: eventually these should be exported somehow
#![allow(unused)]
use core::intrinsics::transmute;
use core::slice;
use core::cmp::min;
use core::mem::size_of;
use Rng;
/// Implement `next_u64` via `next_u32`, little-endian order.
pub fn next_u64_via_u32<R: Rng+?Sized>(rng: &mut R) -> u64 {
// Use LE; we explicitly generate one value before the next.
let x = rng.next_u32() as u64;
let y = rng.next_u32() as u64;
(y << 32) | x
}
macro_rules! fill_bytes_via {
($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{
let mut left = $dest;
while left.len() >= $BYTES {
let (l, r) = {left}.split_at_mut($BYTES);
left = r;
let chunk: [u8; $BYTES] = unsafe {
transmute($rng.$next_u().to_le())
};
l.copy_from_slice(&chunk);
}
let n = left.len();
if n > 0 {
let chunk: [u8; $BYTES] = unsafe {
transmute($rng.$next_u().to_le())
};
left.copy_from_slice(&chunk[..n]);
}
}}
}
/// Implement `fill_bytes` via `next_u32`, little-endian order.
pub fn fill_bytes_via_u32<R: Rng+?Sized>(rng: &mut R, dest: &mut [u8]) {
fill_bytes_via!(rng, next_u32, 4, dest)
}
/// Implement `fill_bytes` via `next_u64`, little-endian order.
pub fn fill_bytes_via_u64<R: Rng+?Sized>(rng: &mut R, dest: &mut [u8]) {
fill_bytes_via!(rng, next_u64, 8, dest)
}
macro_rules! impl_uint_from_fill {
($rng:expr, $ty:ty, $N:expr) => ({
debug_assert!($N == size_of::<$ty>());
let mut int: $ty = 0;
unsafe {
let ptr = &mut int as *mut $ty as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, $N);
$rng.fill_bytes(slice);
}
int
});
}
macro_rules! fill_via_chunks {
($src:expr, $dest:expr, $N:expr) => ({
let chunk_size_u8 = min($src.len() * $N, $dest.len());
let chunk_size = (chunk_size_u8 + $N - 1) / $N;
// Convert to little-endian:
for ref mut x in $src[0..chunk_size].iter_mut() {
**x = (*x).to_le();
}
let bytes = unsafe { slice::from_raw_parts($src.as_ptr() as *const u8,
$src.len() * $N) };
let dest_chunk = &mut $dest[0..chunk_size_u8];
dest_chunk.copy_from_slice(&bytes[0..chunk_size_u8]);
(chunk_size, chunk_size_u8)
});
}
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u32, filled_u8)`.
///
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u32` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 4` rounded up.
///
/// Note that on big-endian systems values in the output buffer `src` are
/// mutated. `src[0..consumed_u32]` get converted to little-endian before
/// copying.
///
/// # Example
/// (from `IsaacRng`)
///
/// ```rust,ignore
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
/// let mut read_len = 0;
/// while read_len < dest.len() {
/// if self.index >= self.rsl.len() {
/// self.isaac();
/// }
///
/// let (consumed_u32, filled_u8) =
/// impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
/// &mut dest[read_len..]);
///
/// self.index += consumed_u32;
/// read_len += filled_u8;
/// }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, 4)
}
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u64, filled_u8)`.
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u64` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 8` rounded up.
///
/// Note that on big-endian systems values in the output buffer `src` are
/// mutated. `src[0..consumed_u64]` get converted to little-endian before
/// copying.
///
/// See `fill_via_u32_chunks` for an example.
pub fn fill_via_u64_chunks(src: &mut [u64], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, 8)
}
/// Implement `next_u32` via `fill_bytes`, little-endian order.
pub fn next_u32_via_fill<R: Rng+?Sized>(rng: &mut R) -> u32 {
impl_uint_from_fill!(rng, u32, 4)
}
/// Implement `next_u64` via `fill_bytes`, little-endian order.
pub fn next_u64_via_fill<R: Rng+?Sized>(rng: &mut R) -> u64 {
impl_uint_from_fill!(rng, u64, 8)
}
// TODO: implement tests for the above

View File

@ -1,635 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// 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.
//! The ISAAC random number generator.
#![allow(non_camel_case_types)]
use std::slice;
use std::iter::repeat;
use std::num::Wrapping as w;
use std::fmt;
use {Rng, SeedableRng, Rand, w32, w64};
const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
const RAND_SIZE_USIZE: usize = 1 << RAND_SIZE_LEN;
/// A random number generator that uses the ISAAC algorithm[1].
///
/// The ISAAC algorithm is generally accepted as suitable for
/// cryptographic purposes, but this implementation has not be
/// verified as such. Prefer a generator like `OsRng` that defers to
/// the operating system for cases that need high security.
///
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
#[derive(Copy)]
pub struct IsaacRng {
cnt: u32,
rsl: [w32; RAND_SIZE_USIZE],
mem: [w32; RAND_SIZE_USIZE],
a: w32,
b: w32,
c: w32,
}
static EMPTY: IsaacRng = IsaacRng {
cnt: 0,
rsl: [w(0); RAND_SIZE_USIZE],
mem: [w(0); RAND_SIZE_USIZE],
a: w(0), b: w(0), c: w(0),
};
impl IsaacRng {
/// Create an ISAAC random number generator using the default
/// fixed seed.
pub fn new_unseeded() -> IsaacRng {
let mut rng = EMPTY;
rng.init(false);
rng
}
/// Initialises `self`. If `use_rsl` is true, then use the current value
/// of `rsl` as a seed, otherwise construct one algorithmically (not
/// randomly).
fn init(&mut self, use_rsl: bool) {
let mut a = w(0x9e3779b9);
let mut b = a;
let mut c = a;
let mut d = a;
let mut e = a;
let mut f = a;
let mut g = a;
let mut h = a;
macro_rules! mix {
() => {{
a=a^(b<<11); d=d+a; b=b+c;
b=b^(c>>2); e=e+b; c=c+d;
c=c^(d<<8); f=f+c; d=d+e;
d=d^(e>>16); g=g+d; e=e+f;
e=e^(f<<10); h=h+e; f=f+g;
f=f^(g>>4); a=a+f; g=g+h;
g=g^(h<<8); b=b+g; h=h+a;
h=h^(a>>9); c=c+h; a=a+b;
}}
}
for _ in 0..4 {
mix!();
}
if use_rsl {
macro_rules! memloop {
($arr:expr) => {{
for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) {
a=a+$arr[i ]; b=b+$arr[i+1];
c=c+$arr[i+2]; d=d+$arr[i+3];
e=e+$arr[i+4]; f=f+$arr[i+5];
g=g+$arr[i+6]; h=h+$arr[i+7];
mix!();
self.mem[i ]=a; self.mem[i+1]=b;
self.mem[i+2]=c; self.mem[i+3]=d;
self.mem[i+4]=e; self.mem[i+5]=f;
self.mem[i+6]=g; self.mem[i+7]=h;
}
}}
}
memloop!(self.rsl);
memloop!(self.mem);
} else {
for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) {
mix!();
self.mem[i ]=a; self.mem[i+1]=b;
self.mem[i+2]=c; self.mem[i+3]=d;
self.mem[i+4]=e; self.mem[i+5]=f;
self.mem[i+6]=g; self.mem[i+7]=h;
}
}
self.isaac();
}
/// Refills the output buffer (`self.rsl`)
#[inline]
fn isaac(&mut self) {
self.c = self.c + w(1);
// abbreviations
let mut a = self.a;
let mut b = self.b + self.c;
const MIDPOINT: usize = RAND_SIZE_USIZE / 2;
macro_rules! ind {
($x:expr) => ( self.mem[($x >> 2usize).0 as usize & (RAND_SIZE_USIZE - 1)] )
}
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
for &(mr_offset, m2_offset) in r.iter() {
macro_rules! rngstepp {
($j:expr, $shift:expr) => {{
let base = $j;
let mix = a << $shift;
let x = self.mem[base + mr_offset];
a = (a ^ mix) + self.mem[base + m2_offset];
let y = ind!(x) + a + b;
self.mem[base + mr_offset] = y;
b = ind!(y >> RAND_SIZE_LEN) + x;
self.rsl[base + mr_offset] = b;
}}
}
macro_rules! rngstepn {
($j:expr, $shift:expr) => {{
let base = $j;
let mix = a >> $shift;
let x = self.mem[base + mr_offset];
a = (a ^ mix) + self.mem[base + m2_offset];
let y = ind!(x) + a + b;
self.mem[base + mr_offset] = y;
b = ind!(y >> RAND_SIZE_LEN) + x;
self.rsl[base + mr_offset] = b;
}}
}
for i in (0..MIDPOINT/4).map(|i| i * 4) {
rngstepp!(i + 0, 13);
rngstepn!(i + 1, 6);
rngstepp!(i + 2, 2);
rngstepn!(i + 3, 16);
}
}
self.a = a;
self.b = b;
self.cnt = RAND_SIZE;
}
}
// Cannot be derived because [u32; 256] does not implement Clone
impl Clone for IsaacRng {
fn clone(&self) -> IsaacRng {
*self
}
}
impl Rng for IsaacRng {
#[inline]
fn next_u32(&mut self) -> u32 {
if self.cnt == 0 {
// make some more numbers
self.isaac();
}
self.cnt -= 1;
// self.cnt is at most RAND_SIZE, but that is before the
// subtraction above. We want to index without bounds
// checking, but this could lead to incorrect code if someone
// misrefactors, so we check, sometimes.
//
// (Changes here should be reflected in Isaac64Rng.next_u64.)
debug_assert!(self.cnt < RAND_SIZE);
// (the % is cheaply telling the optimiser that we're always
// in bounds, without unsafe. NB. this is a power of two, so
// it optimises to a bitwise mask).
self.rsl[(self.cnt % RAND_SIZE) as usize].0
}
}
impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
fn reseed(&mut self, seed: &'a [u32]) {
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
// - 1], 0, 0, ...], to fill rng.rsl.
let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u32));
for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) {
*rsl_elem = w(seed_elem);
}
self.cnt = 0;
self.a = w(0);
self.b = w(0);
self.c = w(0);
self.init(true);
}
/// Create an ISAAC random number generator with a seed. This can
/// be any length, although the maximum number of elements used is
/// 256 and any more will be silently ignored. A generator
/// constructed with a given seed will generate the same sequence
/// of values as all other generators constructed with that seed.
fn from_seed(seed: &'a [u32]) -> IsaacRng {
let mut rng = EMPTY;
rng.reseed(seed);
rng
}
}
impl Rand for IsaacRng {
fn rand<R: Rng>(other: &mut R) -> IsaacRng {
let mut ret = EMPTY;
unsafe {
let ptr = ret.rsl.as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_USIZE * 4);
other.fill_bytes(slice);
}
ret.cnt = 0;
ret.a = w(0);
ret.b = w(0);
ret.c = w(0);
ret.init(true);
return ret;
}
}
impl fmt::Debug for IsaacRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IsaacRng {{}}")
}
}
const RAND_SIZE_64_LEN: usize = 8;
const RAND_SIZE_64: usize = 1 << RAND_SIZE_64_LEN;
/// A random number generator that uses ISAAC-64[1], the 64-bit
/// variant of the ISAAC algorithm.
///
/// The ISAAC algorithm is generally accepted as suitable for
/// cryptographic purposes, but this implementation has not be
/// verified as such. Prefer a generator like `OsRng` that defers to
/// the operating system for cases that need high security.
///
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
#[derive(Copy)]
pub struct Isaac64Rng {
cnt: usize,
rsl: [w64; RAND_SIZE_64],
mem: [w64; RAND_SIZE_64],
a: w64,
b: w64,
c: w64,
}
static EMPTY_64: Isaac64Rng = Isaac64Rng {
cnt: 0,
rsl: [w(0); RAND_SIZE_64],
mem: [w(0); RAND_SIZE_64],
a: w(0), b: w(0), c: w(0),
};
impl Isaac64Rng {
/// Create a 64-bit ISAAC random number generator using the
/// default fixed seed.
pub fn new_unseeded() -> Isaac64Rng {
let mut rng = EMPTY_64;
rng.init(false);
rng
}
/// Initialises `self`. If `use_rsl` is true, then use the current value
/// of `rsl` as a seed, otherwise construct one algorithmically (not
/// randomly).
fn init(&mut self, use_rsl: bool) {
macro_rules! init {
($var:ident) => (
let mut $var = w(0x9e3779b97f4a7c13);
)
}
init!(a); init!(b); init!(c); init!(d);
init!(e); init!(f); init!(g); init!(h);
macro_rules! mix {
() => {{
a=a-e; f=f^(h>>9); h=h+a;
b=b-f; g=g^(a<<9); a=a+b;
c=c-g; h=h^(b>>23); b=b+c;
d=d-h; a=a^(c<<15); c=c+d;
e=e-a; b=b^(d>>14); d=d+e;
f=f-b; c=c^(e<<20); e=e+f;
g=g-c; d=d^(f>>17); f=f+g;
h=h-d; e=e^(g<<14); g=g+h;
}}
}
for _ in 0..4 {
mix!();
}
if use_rsl {
macro_rules! memloop {
($arr:expr) => {{
for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
a=a+$arr[i ]; b=b+$arr[i+1];
c=c+$arr[i+2]; d=d+$arr[i+3];
e=e+$arr[i+4]; f=f+$arr[i+5];
g=g+$arr[i+6]; h=h+$arr[i+7];
mix!();
self.mem[i ]=a; self.mem[i+1]=b;
self.mem[i+2]=c; self.mem[i+3]=d;
self.mem[i+4]=e; self.mem[i+5]=f;
self.mem[i+6]=g; self.mem[i+7]=h;
}
}}
}
memloop!(self.rsl);
memloop!(self.mem);
} else {
for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
mix!();
self.mem[i ]=a; self.mem[i+1]=b;
self.mem[i+2]=c; self.mem[i+3]=d;
self.mem[i+4]=e; self.mem[i+5]=f;
self.mem[i+6]=g; self.mem[i+7]=h;
}
}
self.isaac64();
}
/// Refills the output buffer (`self.rsl`)
fn isaac64(&mut self) {
self.c = self.c + w(1);
// abbreviations
let mut a = self.a;
let mut b = self.b + self.c;
const MIDPOINT: usize = RAND_SIZE_64 / 2;
const MP_VEC: [(usize, usize); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
macro_rules! ind {
($x:expr) => {
*self.mem.get_unchecked((($x >> 3usize).0 as usize) & (RAND_SIZE_64 - 1))
}
}
for &(mr_offset, m2_offset) in MP_VEC.iter() {
for base in (0..MIDPOINT / 4).map(|i| i * 4) {
macro_rules! rngstepp {
($j:expr, $shift:expr) => {{
let base = base + $j;
let mix = a ^ (a << $shift);
let mix = if $j == 0 {!mix} else {mix};
unsafe {
let x = *self.mem.get_unchecked(base + mr_offset);
a = mix + *self.mem.get_unchecked(base + m2_offset);
let y = ind!(x) + a + b;
*self.mem.get_unchecked_mut(base + mr_offset) = y;
b = ind!(y >> RAND_SIZE_64_LEN) + x;
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
}
}}
}
macro_rules! rngstepn {
($j:expr, $shift:expr) => {{
let base = base + $j;
let mix = a ^ (a >> $shift);
let mix = if $j == 0 {!mix} else {mix};
unsafe {
let x = *self.mem.get_unchecked(base + mr_offset);
a = mix + *self.mem.get_unchecked(base + m2_offset);
let y = ind!(x) + a + b;
*self.mem.get_unchecked_mut(base + mr_offset) = y;
b = ind!(y >> RAND_SIZE_64_LEN) + x;
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
}
}}
}
rngstepp!(0, 21);
rngstepn!(1, 5);
rngstepp!(2, 12);
rngstepn!(3, 33);
}
}
self.a = a;
self.b = b;
self.cnt = RAND_SIZE_64;
}
}
// Cannot be derived because [u32; 256] does not implement Clone
impl Clone for Isaac64Rng {
fn clone(&self) -> Isaac64Rng {
*self
}
}
impl Rng for Isaac64Rng {
// FIXME #7771: having next_u32 like this should be unnecessary
#[inline]
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
#[inline]
fn next_u64(&mut self) -> u64 {
if self.cnt == 0 {
// make some more numbers
self.isaac64();
}
self.cnt -= 1;
// See corresponding location in IsaacRng.next_u32 for
// explanation.
debug_assert!(self.cnt < RAND_SIZE_64);
self.rsl[(self.cnt % RAND_SIZE_64) as usize].0
}
}
impl<'a> SeedableRng<&'a [u64]> for Isaac64Rng {
fn reseed(&mut self, seed: &'a [u64]) {
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
// - 1], 0, 0, ...], to fill rng.rsl.
let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u64));
for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) {
*rsl_elem = w(seed_elem);
}
self.cnt = 0;
self.a = w(0);
self.b = w(0);
self.c = w(0);
self.init(true);
}
/// Create an ISAAC random number generator with a seed. This can
/// be any length, although the maximum number of elements used is
/// 256 and any more will be silently ignored. A generator
/// constructed with a given seed will generate the same sequence
/// of values as all other generators constructed with that seed.
fn from_seed(seed: &'a [u64]) -> Isaac64Rng {
let mut rng = EMPTY_64;
rng.reseed(seed);
rng
}
}
impl Rand for Isaac64Rng {
fn rand<R: Rng>(other: &mut R) -> Isaac64Rng {
let mut ret = EMPTY_64;
unsafe {
let ptr = ret.rsl.as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_64 * 8);
other.fill_bytes(slice);
}
ret.cnt = 0;
ret.a = w(0);
ret.b = w(0);
ret.c = w(0);
ret.init(true);
return ret;
}
}
impl fmt::Debug for Isaac64Rng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Isaac64Rng {{}}")
}
}
#[cfg(test)]
mod test {
use {Rng, SeedableRng};
use super::{IsaacRng, Isaac64Rng};
#[test]
fn test_rng_32_rand_seeded() {
let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
let mut ra: IsaacRng = SeedableRng::from_seed(&s[..]);
let mut rb: IsaacRng = SeedableRng::from_seed(&s[..]);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_64_rand_seeded() {
let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
let mut ra: Isaac64Rng = SeedableRng::from_seed(&s[..]);
let mut rb: Isaac64Rng = SeedableRng::from_seed(&s[..]);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_32_seeded() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_64_seeded() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_32_reseed() {
let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
let mut r: IsaacRng = SeedableRng::from_seed(&s[..]);
let string1: String = r.gen_ascii_chars().take(100).collect();
r.reseed(&s[..]);
let string2: String = r.gen_ascii_chars().take(100).collect();
assert_eq!(string1, string2);
}
#[test]
fn test_rng_64_reseed() {
let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
let mut r: Isaac64Rng = SeedableRng::from_seed(&s[..]);
let string1: String = r.gen_ascii_chars().take(100).collect();
r.reseed(&s[..]);
let string2: String = r.gen_ascii_chars().take(100).collect();
assert_eq!(string1, string2);
}
#[test]
fn test_rng_32_true_values() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = (0..10).map(|_| ra.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709,
4203127393, 264982119, 2765226902, 2737944514, 3900253796));
let seed: &[_] = &[12345, 67890, 54321, 9876];
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
for _ in 0..10000 { rb.next_u32(); }
let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
vec!(3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
1576568959, 3507990155, 179069555, 141456972, 2478885421));
}
#[test]
fn test_rng_64_true_values() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = (0..10).map(|_| ra.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
vec!(547121783600835980, 14377643087320773276, 17351601304698403469,
1238879483818134882, 11952566807690396487, 13970131091560099343,
4469761996653280935, 15552757044682284409, 6860251611068737823,
13722198873481261842));
let seed: &[_] = &[12345, 67890, 54321, 9876];
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
for _ in 0..10000 { rb.next_u64(); }
let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
vec!(18143823860592706164, 8491801882678285927, 2699425367717515619,
17196852593171130876, 2606123525235546165, 15790932315217671084,
596345674630742204, 9947027391921273664, 11788097613744130851,
10391409374914919106));
}
#[test]
fn test_rng_clone() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);
let mut clone = rng.clone();
for _ in 0..16 {
assert_eq!(rng.next_u64(), clone.next_u64());
}
}
}

739
src/jitter.rs Normal file
View File

@ -0,0 +1,739 @@
// Copyright 2017 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.
//
// Based on jitterentropy-library, http://www.chronox.de/jent.html.
// Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017.
//
// With permission from Stephan Mueller to relicense the Rust translation under
// the MIT license.
//! Non-physical true random number generator based on timing jitter.
use {Rng, impls};
use core::{fmt, mem, ptr};
#[cfg(feature="std")]
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
const MEMORY_BLOCKS: usize = 64;
const MEMORY_BLOCKSIZE: usize = 32;
const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;
/// A true random number generator based on jitter in the CPU execution time,
/// and jitter in memory access time.
///
/// This is a true random number generator, as opposed to pseudo-random
/// generators. Random numbers generated by `JitterRng` can be seen as fresh
/// entropy. A consequence is that is orders of magnitude slower than `OsRng`
/// and PRNGs (about 10^3 .. 10^6 slower).
///
/// There are very few situations where using this RNG is appropriate. Only very
/// few applications require true entropy. A normal PRNG can be statistically
/// indistinguishable, and a cryptographic PRNG should also be as impossible to
/// predict.
///
/// Use of `JitterRng` is recommended for initializing cryptographic PRNGs when
/// `OsRng` is not available.
///
/// This implementation is based on
/// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0.
//
// Note: the C implementation relies on being compiled without optimizations.
// This implementation goes through lengths to make the compiler not optimise
// out what is technically dead code, but that does influence timing jitter.
pub struct JitterRng {
data: u64, // Actual random number
// Number of rounds to run the entropy collector per 64 bits
rounds: u32,
// Timer and previous time stamp, used by `measure_jitter`
timer: fn() -> u64,
prev_time: u64,
// Deltas used for the stuck test
last_delta: i64,
last_delta2: i64,
// Memory for the Memory Access noise source
mem_prev_index: usize,
mem: [u8; MEMORY_SIZE],
// Make `next_u32` not waste 32 bits
data_remaining: Option<u32>,
}
// Custom Debug implementation that does not expose the internal state
impl fmt::Debug for JitterRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "JitterRng {{}}")
}
}
/// An error that can occur when `test_timer` fails.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimerError {
/// No timer available.
NoTimer,
/// Timer too coarse to use as an entropy source.
CoarseTimer,
/// Timer is not monotonically increasing.
NotMonotonic,
/// Variations of deltas of time too small.
TinyVariantions,
/// Too many stuck results (indicating no added entropy).
TooManyStuck,
#[doc(hidden)]
__Nonexhaustive,
}
impl TimerError {
fn description(&self) -> &'static str {
match *self {
TimerError::NoTimer => "no timer available",
TimerError::CoarseTimer => "coarse timer",
TimerError::NotMonotonic => "timer not monotonic",
TimerError::TinyVariantions => "time delta variations too small",
TimerError::TooManyStuck => "too many stuck results",
TimerError::__Nonexhaustive => unreachable!(),
}
}
}
impl fmt::Display for TimerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[cfg(feature="std")]
impl ::std::error::Error for TimerError {
fn description(&self) -> &str {
self.description()
}
}
// Initialise to zero; must be positive
#[cfg(feature="std")]
static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT;
impl JitterRng {
/// Create a new `JitterRng`.
/// Makes use of `std::time` for a timer.
///
/// During initialization CPU execution timing jitter is measured a few
/// hundred times. If this does not pass basic quality tests, an error is
/// returned. The test result is cached to make subsequent calls faster.
#[cfg(feature="std")]
pub fn new() -> Result<JitterRng, TimerError> {
let mut ec = JitterRng::new_with_timer(platform::get_nstime);
let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u32;
if rounds == 0 {
// No result yet: run test.
// This allows the timer test to run multiple times; we don't care.
rounds = ec.test_timer()?;
JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed);
}
ec.set_rounds(rounds);
Ok(ec)
}
/// Create a new `JitterRng`.
/// A custom timer can be supplied, making it possible to use `JitterRng` in
/// `no_std` environments.
///
/// The timer must have nanosecond precision.
///
/// This method is more low-level than `new()`. It is the responsibility of
/// the caller to run `test_timer` before using any numbers generated with
/// `JitterRng`, and optionally call `set_rounds()`.
pub fn new_with_timer(timer: fn() -> u64) -> JitterRng {
let mut ec = JitterRng {
data: 0,
rounds: 64,
timer: timer,
prev_time: 0,
last_delta: 0,
last_delta2: 0,
mem_prev_index: 0,
mem: [0; MEMORY_SIZE],
data_remaining: None,
};
// Fill `data`, `prev_time`, `last_delta` and `last_delta2` with
// non-zero values.
ec.prev_time = timer();
ec.gen_entropy();
// Do a single read from `self.mem` to make sure the Memory Access noise
// source is not optimised out.
// Note: this read is important, it effects optimisations for the entire
// module!
black_box(ec.mem[0]);
ec
}
/// Configures how many rounds are used to generate each 64-bit value.
/// This must be greater than zero, and has a big impact on performance
/// and output quality.
///
/// `new_with_timer` conservatively uses 64 rounds, but often less rounds
/// can be used. The `test_timer()` function returns the minimum number of
/// rounds required for full strength (platform dependent), so one may use
/// `rng.set_rounds(rng.test_timer()?);` or cache the value.
pub fn set_rounds(&mut self, rounds: u32) {
assert!(rounds > 0);
self.rounds = rounds;
}
// Calculate a random loop count used for the next round of an entropy
// collection, based on bits from a fresh value from the timer.
//
// The timer is folded to produce a number that contains at most `n_bits`
// bits.
//
// Note: A constant should be added to the resulting random loop count to
// prevent loops that run 0 times.
#[inline(never)]
fn random_loop_cnt(&mut self, n_bits: u32) -> u32 {
let mut rounds = 0;
let mut time = (self.timer)();
// Mix with the current state of the random number balance the random
// loop counter a bit more.
time ^= self.data;
// We fold the time value as much as possible to ensure that as many
// bits of the time stamp are included as possible.
let folds = (64 + n_bits - 1) / n_bits;
let mask = (1 << n_bits) - 1;
for _ in 0..folds {
rounds ^= time & mask;
time = time >> n_bits;
}
rounds as u32
}
// CPU jitter noise source
// Noise source based on the CPU execution time jitter
//
// This function injects the individual bits of the time value into the
// entropy pool using an LFSR.
//
// The code is deliberately inefficient with respect to the bit shifting.
// This function not only acts as folding operation, but this function's
// execution is used to measure the CPU execution time jitter. Any change to
// the loop in this function implies that careful retesting must be done.
#[inline(never)]
fn lfsr_time(&mut self, time: u64, var_rounds: bool) {
fn lfsr(mut data: u64, time: u64) -> u64{
for i in 1..65 {
let mut tmp = time << (64 - i);
tmp = tmp >> (64 - 1);
// Fibonacci LSFR with polynomial of
// x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is
// primitive according to
// http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf
// (the shift values are the polynomial values minus one
// due to counting bits from 0 to 63). As the current
// position is always the LSB, the polynomial only needs
// to shift data in from the left without wrap.
data ^= tmp;
data ^= (data >> 63) & 1;
data ^= (data >> 60) & 1;
data ^= (data >> 55) & 1;
data ^= (data >> 30) & 1;
data ^= (data >> 27) & 1;
data ^= (data >> 22) & 1;
data = data.rotate_left(1);
}
data
}
// Note: in the reference implementation only the last round effects
// `self.data`, all the other results are ignored. To make sure the
// other rounds are not optimised out, we first run all but the last
// round on a throw-away value instead of the real `self.data`.
let mut lfsr_loop_cnt = 0;
if var_rounds { lfsr_loop_cnt = self.random_loop_cnt(4) };
let mut throw_away: u64 = 0;
for _ in 0..lfsr_loop_cnt {
throw_away = lfsr(throw_away, time);
}
black_box(throw_away);
self.data = lfsr(self.data, time);
}
// Memory Access noise source
// This is a noise source based on variations in memory access times
//
// This function performs memory accesses which will add to the timing
// variations due to an unknown amount of CPU wait states that need to be
// added when accessing memory. The memory size should be larger than the L1
// caches as outlined in the documentation and the associated testing.
//
// The L1 cache has a very high bandwidth, albeit its access rate is usually
// slower than accessing CPU registers. Therefore, L1 accesses only add
// minimal variations as the CPU has hardly to wait. Starting with L2,
// significant variations are added because L2 typically does not belong to
// the CPU any more and therefore a wider range of CPU wait states is
// necessary for accesses. L3 and real memory accesses have even a wider
// range of wait states. However, to reliably access either L3 or memory,
// the `self.mem` memory must be quite large which is usually not desirable.
#[inline(never)]
fn memaccess(&mut self, var_rounds: bool) {
let mut acc_loop_cnt = 128;
if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) };
let mut index = self.mem_prev_index;
for _ in 0..acc_loop_cnt {
// Addition of memblocksize - 1 to index with wrap around logic to
// ensure that every memory location is hit evenly.
// The modulus also allows the compiler to remove the indexing
// bounds check.
index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE;
// memory access: just add 1 to one byte
// memory access implies read from and write to memory location
let tmp = self.mem[index];
self.mem[index] = tmp.wrapping_add(1);
}
self.mem_prev_index = index;
}
// Stuck test by checking the:
// - 1st derivation of the jitter measurement (time delta)
// - 2nd derivation of the jitter measurement (delta of time deltas)
// - 3rd derivation of the jitter measurement (delta of delta of time
// deltas)
//
// All values must always be non-zero.
// This test is a heuristic to see whether the last measurement holds
// entropy.
fn stuck(&mut self, current_delta: i64) -> bool {
let delta2 = self.last_delta - current_delta;
let delta3 = delta2 - self.last_delta2;
self.last_delta = current_delta;
self.last_delta2 = delta2;
current_delta == 0 || delta2 == 0 || delta3 == 0
}
// This is the heart of the entropy generation: calculate time deltas and
// use the CPU jitter in the time deltas. The jitter is injected into the
// entropy pool.
//
// Ensure that `self.prev_time` is primed before using the output of this
// function. This can be done by calling this function and not using its
// result.
fn measure_jitter(&mut self) -> Option<()> {
// Invoke one noise source before time measurement to add variations
self.memaccess(true);
// Get time stamp and calculate time delta to previous
// invocation to measure the timing variations
let time = (self.timer)();
// Note: wrapping_sub combined with a cast to `i64` generates a correct
// delta, even in the unlikely case this is a timer that is not strictly
// monotonic.
let current_delta = time.wrapping_sub(self.prev_time) as i64;
self.prev_time = time;
// Call the next noise source which also injects the data
self.lfsr_time(current_delta as u64, true);
// Check whether we have a stuck measurement (i.e. does the last
// measurement holds entropy?).
if self.stuck(current_delta) { return None };
// Rotate the data buffer by a prime number (any odd number would
// do) to ensure that every bit position of the input time stamp
// has an even chance of being merged with a bit position in the
// entropy pool. We do not use one here as the adjacent bits in
// successive time deltas may have some form of dependency. The
// chosen value of 7 implies that the low 7 bits of the next
// time delta value is concatenated with the current time delta.
self.data = self.data.rotate_left(7);
Some(())
}
// Shuffle the pool a bit by mixing some value with a bijective function
// (XOR) into the pool.
//
// The function generates a mixer value that depends on the bits set and
// the location of the set bits in the random number generated by the
// entropy source. Therefore, based on the generated random number, this
// mixer value can have 2^64 different values. That mixer value is
// initialized with the first two SHA-1 constants. After obtaining the
// mixer value, it is XORed into the random number.
//
// The mixer value is not assumed to contain any entropy. But due to the
// XOR operation, it can also not destroy any entropy present in the
// entropy pool.
#[inline(never)]
fn stir_pool(&mut self) {
// This constant is derived from the first two 32 bit initialization
// vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1
// The order does not really matter as we do not rely on the specific
// numbers. We just pick the SHA-1 constants as they have a good mix of
// bit set and unset.
const CONSTANT: u64 = 0x67452301efcdab89;
// The start value of the mixer variable is derived from the third
// and fourth 32 bit initialization vector of SHA-1 as defined in
// FIPS 180-4 section 5.3.1
let mut mixer = 0x98badcfe10325476;
// This is a constant time function to prevent leaking timing
// information about the random number.
// The normal code is:
// ```
// for i in 0..64 {
// if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; }
// }
// ```
// This is a bit fragile, as LLVM really wants to use branches here, and
// we rely on it to not recognise the opportunity.
for i in 0..64 {
let apply = (self.data >> i) & 1;
let mask = !apply.wrapping_sub(1);
mixer ^= CONSTANT & mask;
mixer = mixer.rotate_left(1);
}
self.data ^= mixer;
}
fn gen_entropy(&mut self) -> u64 {
// Prime `self.prev_time`, and run the noice sources to make sure the
// first loop round collects the expected entropy.
let _ = self.measure_jitter();
for _ in 0..self.rounds {
// If a stuck measurement is received, repeat measurement
// Note: we do not guard against an infinite loop, that would mean
// the timer suddenly became broken.
while self.measure_jitter().is_none() {}
}
self.stir_pool();
self.data
}
/// Basic quality tests on the timer, by measuring CPU timing jitter a few
/// hundred times.
///
/// If succesful, this will return the estimated number of rounds necessary
/// to collect 64 bits of entropy. Otherwise a `TimerError` with the cause
/// of the failure will be returned.
pub fn test_timer(&mut self) -> Result<u32, TimerError> {
// We could add a check for system capabilities such as `clock_getres`
// or check for `CONFIG_X86_TSC`, but it does not make much sense as the
// following sanity checks verify that we have a high-resolution timer.
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
return Err(TimerError::NoTimer);
let mut delta_sum = 0;
let mut old_delta = 0;
let mut time_backwards = 0;
let mut count_mod = 0;
let mut count_stuck = 0;
// TESTLOOPCOUNT needs some loops to identify edge systems.
// 100 is definitely too little.
const TESTLOOPCOUNT: u64 = 300;
const CLEARCACHE: u64 = 100;
for i in 0..(CLEARCACHE + TESTLOOPCOUNT) {
// Measure time delta of core entropy collection logic
let time = (self.timer)();
self.memaccess(true);
self.lfsr_time(time, true);
let time2 = (self.timer)();
// Test whether timer works
if time == 0 || time2 == 0 {
return Err(TimerError::NoTimer);
}
let delta = time2.wrapping_sub(time) as i64;
// Test whether timer is fine grained enough to provide delta even
// when called shortly after each other -- this implies that we also
// have a high resolution timer
if delta == 0 {
return Err(TimerError::CoarseTimer);
}
// Up to here we did not modify any variable that will be
// evaluated later, but we already performed some work. Thus we
// already have had an impact on the caches, branch prediction,
// etc. with the goal to clear it to get the worst case
// measurements.
if i < CLEARCACHE { continue; }
if self.stuck(delta) { count_stuck += 1; }
// Test whether we have an increasing timer.
if !(time2 > time) { time_backwards += 1; }
// Count the number of times the counter increases in steps of 100ns
// or greater.
if (delta % 100) == 0 { count_mod += 1; }
// Ensure that we have a varying delta timer which is necessary for
// the calculation of entropy -- perform this check only after the
// first loop is executed as we need to prime the old_delta value
delta_sum += (delta - old_delta).abs() as u64;
old_delta = delta;
}
// We allow the time to run backwards for up to three times.
// This can happen if the clock is being adjusted by NTP operations.
// If such an operation just happens to interfere with our test, it
// should not fail. The value of 3 should cover the NTP case being
// performed during our test run.
if time_backwards > 3 {
return Err(TimerError::NotMonotonic);
}
// Test that the available amount of entropy per round does not get to
// low. We expect 1 bit of entropy per round as a reasonable minimum
// (although less is possible, it means the collector loop has to run
// much more often).
// `assert!(delta_average >= log2(1))`
// `assert!(delta_sum / TESTLOOPCOUNT >= 1)`
// `assert!(delta_sum >= TESTLOOPCOUNT)`
if delta_sum < TESTLOOPCOUNT {
return Err(TimerError::TinyVariantions);
}
// Ensure that we have variations in the time stamp below 100 for at
// least 10% of all checks -- on some platforms, the counter increments
// in multiples of 100, but not always
if count_mod > (TESTLOOPCOUNT * 9 / 10) {
return Err(TimerError::CoarseTimer);
}
// If we have more than 90% stuck results, then this Jitter RNG is
// likely to not work well.
if count_stuck > (TESTLOOPCOUNT * 9 / 10) {
return Err(TimerError::TooManyStuck);
}
// Estimate the number of `measure_jitter` rounds necessary for 64 bits
// of entropy.
//
// We don't try very hard to come up with a good estimate of the
// available bits of entropy per round here for two reasons:
// 1. Simple estimates of the available bits (like Shannon entropy) are
// too optimistic.
// 2) Unless we want to waste a lot of time during intialization, there
// only a small number of samples are available.
//
// Therefore we use a very simple and conservative estimate:
// `let bits_of_entropy = log2(delta_average) / 2`.
//
// The number of rounds `measure_jitter` should run to collect 64 bits
// of entropy is `64 / bits_of_entropy`.
//
// To have smaller rounding errors, intermediate values are multiplied
// by `FACTOR`. To compensate for `log2` and division rounding down,
// add 1.
let delta_average = delta_sum / TESTLOOPCOUNT;
// println!("delta_average: {}", delta_average);
const FACTOR: u32 = 3;
fn log2(x: u64) -> u32 { 64 - x.leading_zeros() }
// pow(δ, FACTOR) must be representable; if you have overflow reduce FACTOR
Ok(64 * 2 * FACTOR / (log2(delta_average.pow(FACTOR)) + 1))
}
/// Statistical test: return the timer delta of one normal run of the
/// `JitterEntropy` entropy collector.
///
/// Setting `var_rounds` to `true` will execute the memory access and the
/// CPU jitter noice sources a variable amount of times (just like a real
/// `JitterEntropy` round).
///
/// Setting `var_rounds` to `false` will execute the noice sources the
/// minimal number of times. This can be used to measure the minimum amount
/// of entropy one round of entropy collector can collect in the worst case.
///
/// # Example
///
/// Use `timer_stats` to run the [NIST SP 800-90B Entropy Estimation Suite]
/// (https://github.com/usnistgov/SP800-90B_EntropyAssessment).
///
/// This is the recommended way to test the quality of `JitterRng`. It
/// should be run before using the RNG on untested hardware, after changes
/// that could effect how the code is optimised, and after major compiler
/// compiler changes, like a new LLVM version.
///
/// First generate two files `jitter_rng_var.bin` and `jitter_rng_var.min`.
///
/// Execute `python noniid_main.py -v jitter_rng_var.bin 8`, and validate it
/// with `restart.py -v jitter_rng_var.bin 8 <min-entropy>`.
/// This number is the expected amount of entropy that is at least available
/// for each round of the entropy collector. This number should be greater
/// than the amount estimated with `64 / test_timer()`.
///
/// Execute `python noniid_main.py -v -u 4 jitter_rng_var.bin 4`, and
/// validate it with `restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>`.
/// This number is the expected amount of entropy that is available in the
/// last 4 bits of the timer delta after running noice sources. Note that
/// a value of 3.70 is the minimum estimated entropy for true randomness.
///
/// Execute `python noniid_main.py -v -u 4 jitter_rng_var.bin 4`, and
/// validate it with `restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>`.
/// This number is the expected amount of entropy that is available to the
/// entropy collecter if both noice sources only run their minimal number of
/// times. This measures the absolute worst-case, and gives a lower bound
/// for the available entropy.
///
/// ```rust,no_run
/// use rand::JitterRng;
///
/// # use std::error::Error;
/// # use std::fs::File;
/// # use std::io::Write;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// fn get_nstime() -> u64 {
/// use std::time::{SystemTime, UNIX_EPOCH};
///
/// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
/// // The correct way to calculate the current time is
/// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
/// // But this is faster, and the difference in terms of entropy is
/// // negligible (log2(10^9) == 29.9).
/// dur.as_secs() << 30 | dur.subsec_nanos() as u64
/// }
///
/// // Do not initialize with `JitterRng::new`, but with `new_with_timer`.
/// // 'new' always runst `test_timer`, and can therefore fail to
/// // initialize. We want to be able to get the statistics even when the
/// // timer test fails.
/// let mut rng = JitterRng::new_with_timer(get_nstime);
///
/// // 1_000_000 results are required for the NIST SP 800-90B Entropy
/// // Estimation Suite
/// // FIXME: this number is smaller here, otherwise the Doc-test is too slow
/// const ROUNDS: usize = 10_000;
/// let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS);
/// let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS);
///
/// for _ in 0..ROUNDS {
/// deltas_variable.push(rng.timer_stats(true) as u8);
/// deltas_minimal.push(rng.timer_stats(false) as u8);
/// }
///
/// // Write out after the statistics collection loop, to not disturb the
/// // test results.
/// File::create("jitter_rng_var.bin")?.write(&deltas_variable)?;
/// File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?;
/// #
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// # try_main().unwrap();
/// # }
/// ```
#[cfg(feature="std")]
pub fn timer_stats(&mut self, var_rounds: bool) -> i64 {
let time = platform::get_nstime();
self.memaccess(var_rounds);
self.lfsr_time(time, var_rounds);
let time2 = platform::get_nstime();
time2.wrapping_sub(time) as i64
}
}
#[cfg(feature="std")]
mod platform {
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows", all(target_arch = "wasm32", not(target_os = "emscripten")))))]
pub fn get_nstime() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
// The correct way to calculate the current time is
// `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
// But this is faster, and the difference in terms of entropy is negligible
// (log2(10^9) == 29.9).
dur.as_secs() << 30 | dur.subsec_nanos() as u64
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn get_nstime() -> u64 {
extern crate libc;
// On Mac OS and iOS std::time::SystemTime only has 1000ns resolution.
// We use `mach_absolute_time` instead. This provides a CPU dependent unit,
// to get real nanoseconds the result should by multiplied by numer/denom
// from `mach_timebase_info`.
// But we are not interested in the exact nanoseconds, just entropy. So we
// use the raw result.
unsafe { libc::mach_absolute_time() }
}
#[cfg(target_os = "windows")]
pub fn get_nstime() -> u64 {
extern crate winapi;
unsafe {
let mut t = super::mem::zeroed();
winapi::um::profileapi::QueryPerformanceCounter(&mut t);
*t.QuadPart() as u64
}
}
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn get_nstime() -> u64 {
unreachable!()
}
}
// A function that is opaque to the optimizer to assist in avoiding dead-code
// elimination. Taken from `bencher`.
fn black_box<T>(dummy: T) -> T {
unsafe {
let ret = ptr::read_volatile(&dummy);
mem::forget(dummy);
ret
}
}
impl Rng for JitterRng {
fn next_u32(&mut self) -> u32 {
// We want to use both parts of the generated entropy
if let Some(high) = self.data_remaining.take() {
high
} else {
let data = self.next_u64();
self.data_remaining = Some((data >> 32) as u32);
data as u32
}
}
fn next_u64(&mut self) -> u64 {
self.gen_entropy()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u64(self, dest)
}
}
// There are no tests included because (1) this is an "external" RNG, so output
// is not reproducible and (2) `test_timer` *will* fail on some platforms.

View File

@ -1,4 +1,4 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // Copyright 2013-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT. // https://rust-lang.org/COPYRIGHT.
// //
@ -26,7 +26,7 @@
//! //!
//! ```toml //! ```toml
//! [dependencies] //! [dependencies]
//! rand = "0.3" //! rand = "0.4"
//! ``` //! ```
//! //!
//! and this to your crate root: //! and this to your crate root:
@ -184,7 +184,7 @@
//! // where the car is. The game host will never open the door with the car. //! // where the car is. The game host will never open the door with the car.
//! fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 { //! fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 {
//! let choices = free_doors(&[car, choice]); //! let choices = free_doors(&[car, choice]);
//! rand::sample(rng, choices.into_iter(), 1)[0] //! rand::seq::sample_slice(rng, &choices, 1)[0]
//! } //! }
//! //!
//! // Returns the door we switch to, given our current choice and //! // Returns the door we switch to, given our current choice and
@ -243,43 +243,60 @@
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![cfg_attr(feature = "i128_support", feature(i128_type))] #![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))]
#![cfg_attr(feature = "i128_support", feature(i128_type, i128))]
#[cfg(test)] #[macro_use] extern crate log; #[cfg(feature="std")] extern crate std as core;
#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
use core::marker;
use core::mem;
#[cfg(feature="std")] use std::cell::RefCell;
#[cfg(feature="std")] use std::io;
#[cfg(feature="std")] use std::rc::Rc;
use std::cell::RefCell; // external rngs
use std::marker; pub use jitter::JitterRng;
use std::mem; #[cfg(feature="std")] pub use os::OsRng;
use std::io;
use std::rc::Rc;
use std::num::Wrapping as w;
pub use os::OsRng;
// pseudo rngs
pub use isaac::{IsaacRng, Isaac64Rng}; pub use isaac::{IsaacRng, Isaac64Rng};
pub use chacha::ChaChaRng; pub use chacha::ChaChaRng;
pub use prng::XorShiftRng;
// local use declarations
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
use IsaacRng as IsaacWordRng; use prng::IsaacRng as IsaacWordRng;
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
use Isaac64Rng as IsaacWordRng; use prng::Isaac64Rng as IsaacWordRng;
use distributions::{Range, IndependentSample}; use distributions::{Range, IndependentSample};
use distributions::range::SampleRange; use distributions::range::SampleRange;
// public modules
pub mod distributions; pub mod distributions;
pub mod isaac; mod impls;
pub mod chacha; pub mod jitter;
#[cfg(feature="std")] pub mod os;
#[cfg(feature="std")] pub mod read;
pub mod reseeding; pub mod reseeding;
mod rand_impls; #[cfg(any(feature="std", feature = "alloc"))] pub mod seq;
pub mod os;
pub mod read; // These tiny modules are here to avoid API breakage, probably only temporarily
pub mod chacha {
//! The ChaCha random number generator.
pub use prng::ChaChaRng;
}
pub mod isaac {
//! The ISAAC random number generator.
pub use prng::{IsaacRng, Isaac64Rng};
}
// private modules
mod rand_impls;
mod prng;
#[allow(bad_style)]
type w64 = w<u64>;
#[allow(bad_style)]
type w32 = w<u32>;
/// A type that can be randomly generated using an `Rng`. /// A type that can be randomly generated using an `Rng`.
/// ///
@ -303,8 +320,8 @@ type w32 = w<u32>;
/// ///
/// [`Open01`]: struct.Open01.html /// [`Open01`]: struct.Open01.html
/// [`Closed01`]: struct.Closed01.html /// [`Closed01`]: struct.Closed01.html
/// [`Exp1`]: struct.Exp1.html /// [`Exp1`]: distributions/exponential/struct.Exp1.html
/// [`StandardNormal`]: struct.StandardNormal.html /// [`StandardNormal`]: distributions/normal/struct.StandardNormal.html
/// ///
/// The following aggregate types also implement `Rand` as long as their /// The following aggregate types also implement `Rand` as long as their
/// component types implement it: /// component types implement it:
@ -313,7 +330,6 @@ type w32 = w<u32>;
/// independently, using its own `Rand` implementation. /// independently, using its own `Rand` implementation.
/// * `Option<T>`: Returns `None` with probability 0.5; otherwise generates a /// * `Option<T>`: Returns `None` with probability 0.5; otherwise generates a
/// random `T` and returns `Some(T)`. /// random `T` and returns `Some(T)`.
pub trait Rand : Sized { pub trait Rand : Sized {
/// Generates a random instance of this type using the specified source of /// Generates a random instance of this type using the specified source of
/// randomness. /// randomness.
@ -322,21 +338,28 @@ pub trait Rand : Sized {
/// A random number generator. /// A random number generator.
pub trait Rng { pub trait Rng {
/// Return the next random u32. /// Return the next random `u32`.
/// ///
/// This rarely needs to be called directly, prefer `r.gen()` to /// Implementations of this trait must implement at least one of
/// `r.next_u32()`. /// `next_u32`, `next_u64` and `fill_bytes` directly. In the case this
// FIXME #rust-lang/rfcs#628: Should be implemented in terms of next_u64 /// function is not implemented directly, it can be implemented using
/// `self.next_u64() as u32` or via `fill_bytes` (TODO: expose helper
/// function).
fn next_u32(&mut self) -> u32; fn next_u32(&mut self) -> u32;
/// Return the next random u64. /// Return the next random `u64`.
/// ///
/// By default this is implemented in terms of `next_u32`. An /// Implementations of this trait must implement at least one of
/// implementation of this trait must provide at least one of /// `next_u32`, `next_u64` and `fill_bytes` directly. In the case this
/// these two methods. Similarly to `next_u32`, this rarely needs /// function is not implemented directly, the default implementation will
/// to be called directly, prefer `r.gen()` to `r.next_u64()`. /// generate values via `next_u32` in little-endian fashion, or this
/// function can be implemented via `fill_bytes` (TODO: expose helper
/// function).
///
/// Types wrapping an inner RNG must not use the default implementation,
/// since the inner RNG's implementation may produce different values.
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
((self.next_u32() as u64) << 32) | (self.next_u32() as u64) impls::next_u64_via_u32(self)
} }
/// Return the next random f32 selected from the half-open /// Return the next random f32 selected from the half-open
@ -393,16 +416,20 @@ pub trait Rng {
/// Fill `dest` with random data. /// Fill `dest` with random data.
/// ///
/// This has a default implementation in terms of `next_u64` and /// Implementations of this trait must implement at least one of
/// `next_u32`, but should be overridden by implementations that /// `next_u32`, `next_u64` and `fill_bytes` directly. In the case this
/// offer a more efficient solution than just calling those /// function is not implemented directly, the default implementation will
/// methods repeatedly. /// generate values via `next_u64` in little-endian fashion.
/// (TODO: expose helper function to allow implementation via `next_u32`.)
/// ///
/// This method does *not* have a requirement to bear any fixed /// There is no requirement on how this method generates values relative to
/// relationship to the other methods, for example, it does *not* /// `next_u32` or `next_u64`; e.g. a `u64` cast to bytes is not required to
/// have to result in the same output as progressively filling /// have the same value as eight bytes filled via this function. There *is*
/// `dest` with `self.gen::<u8>()`, and any such behaviour should /// a requirement of portability for reproducible generators which implies
/// not be relied upon. /// that any seedable generator must fix endianness when generating bytes.
///
/// Types wrapping an inner RNG must not use the default implementation,
/// since the inner RNG's implementation may produce different values.
/// ///
/// This method should guarantee that `dest` is entirely filled /// This method should guarantee that `dest` is entirely filled
/// with new data, and may panic if this is impossible /// with new data, and may panic if this is impossible
@ -419,27 +446,7 @@ pub trait Rng {
/// println!("{:?}", &v[..]); /// println!("{:?}", &v[..]);
/// ``` /// ```
fn fill_bytes(&mut self, dest: &mut [u8]) { fn fill_bytes(&mut self, dest: &mut [u8]) {
// this could, in theory, be done by transmuting dest to a impls::fill_bytes_via_u64(self, dest)
// [u64], but this is (1) likely to be undefined behaviour for
// LLVM, (2) has to be very careful about alignment concerns,
// (3) adds more `unsafe` that needs to be checked, (4)
// probably doesn't give much performance gain if
// optimisations are on.
let mut count = 0;
let mut num = 0;
for byte in dest.iter_mut() {
if count == 0 {
// we could micro-optimise here by generating a u32 if
// we only need a few more bytes to fill the vector
// (i.e. at most 4).
num = self.next_u64();
count = 8;
}
*byte = (num & 0xff) as u8;
num >>= 8;
count -= 1;
}
} }
/// Return a random value of a `Rand` type. /// Return a random value of a `Rand` type.
@ -617,6 +624,7 @@ impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng {
} }
} }
#[cfg(feature="std")]
impl<R: ?Sized> Rng for Box<R> where R: Rng { impl<R: ?Sized> Rng for Box<R> where R: Rng {
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
(**self).next_u32() (**self).next_u32()
@ -714,93 +722,6 @@ pub trait SeedableRng<Seed>: Rng {
fn from_seed(seed: Seed) -> Self; fn from_seed(seed: Seed) -> Self;
} }
/// An Xorshift[1] random number
/// generator.
///
/// The Xorshift algorithm is not suitable for cryptographic purposes
/// but is very fast. If you do not know for sure that it fits your
/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
///
/// [1]: Marsaglia, George (July 2003). ["Xorshift
/// RNGs"](https://www.jstatsoft.org/v08/i14/paper). *Journal of
/// Statistical Software*. Vol. 8 (Issue 14).
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug)]
pub struct XorShiftRng {
x: w32,
y: w32,
z: w32,
w: w32,
}
impl XorShiftRng {
/// Creates a new XorShiftRng instance which is not seeded.
///
/// The initial values of this RNG are constants, so all generators created
/// by this function will yield the same stream of random numbers. It is
/// highly recommended that this is created through `SeedableRng` instead of
/// this function
pub fn new_unseeded() -> XorShiftRng {
XorShiftRng {
x: w(0x193a6754),
y: w(0xa8a7d469),
z: w(0x97830e05),
w: w(0x113ba7bb),
}
}
}
impl Rng for XorShiftRng {
#[inline]
fn next_u32(&mut self) -> u32 {
let x = self.x;
let t = x ^ (x << 11);
self.x = self.y;
self.y = self.z;
self.z = self.w;
let w_ = self.w;
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
self.w.0
}
}
impl SeedableRng<[u32; 4]> for XorShiftRng {
/// Reseed an XorShiftRng. This will panic if `seed` is entirely 0.
fn reseed(&mut self, seed: [u32; 4]) {
assert!(!seed.iter().all(|&x| x == 0),
"XorShiftRng.reseed called with an all zero seed.");
self.x = w(seed[0]);
self.y = w(seed[1]);
self.z = w(seed[2]);
self.w = w(seed[3]);
}
/// Create a new XorShiftRng. This will panic if `seed` is entirely 0.
fn from_seed(seed: [u32; 4]) -> XorShiftRng {
assert!(!seed.iter().all(|&x| x == 0),
"XorShiftRng::from_seed called with an all zero seed.");
XorShiftRng {
x: w(seed[0]),
y: w(seed[1]),
z: w(seed[2]),
w: w(seed[3]),
}
}
}
impl Rand for XorShiftRng {
fn rand<R: Rng>(rng: &mut R) -> XorShiftRng {
let mut tuple: (u32, u32, u32, u32) = rng.gen();
while tuple == (0, 0, 0, 0) {
tuple = rng.gen();
}
let (x, y, z, w_) = tuple;
XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }
}
}
/// A wrapper for generating floating point numbers uniformly in the /// A wrapper for generating floating point numbers uniformly in the
/// open interval `(0,1)` (not including either endpoint). /// open interval `(0,1)` (not including either endpoint).
/// ///
@ -838,7 +759,7 @@ pub struct Closed01<F>(pub F);
/// The standard RNG. This is designed to be efficient on the current /// The standard RNG. This is designed to be efficient on the current
/// platform. /// platform.
#[derive(Copy, Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdRng { pub struct StdRng {
rng: IsaacWordRng, rng: IsaacWordRng,
} }
@ -855,8 +776,19 @@ impl StdRng {
/// ///
/// Reading the randomness from the OS may fail, and any error is /// Reading the randomness from the OS may fail, and any error is
/// propagated via the `io::Result` return value. /// propagated via the `io::Result` return value.
#[cfg(feature="std")]
pub fn new() -> io::Result<StdRng> { pub fn new() -> io::Result<StdRng> {
OsRng::new().map(|mut r| StdRng { rng: r.gen() }) match OsRng::new() {
Ok(mut r) => Ok(StdRng { rng: r.gen() }),
Err(e1) => {
match JitterRng::new() {
Ok(mut r) => Ok(StdRng { rng: r.gen() }),
Err(_) => {
Err(e1)
}
}
}
}
} }
} }
@ -870,6 +802,11 @@ impl Rng for StdRng {
fn next_u64(&mut self) -> u64 { fn next_u64(&mut self) -> u64 {
self.rng.next_u64() self.rng.next_u64()
} }
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.rng.fill_bytes(dest)
}
} }
impl<'a> SeedableRng<&'a [usize]> for StdRng { impl<'a> SeedableRng<&'a [usize]> for StdRng {
@ -891,31 +828,33 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
/// seeded `Rng` for consistency over time you should pick one algorithm and /// seeded `Rng` for consistency over time you should pick one algorithm and
/// create the `Rng` yourself. /// create the `Rng` yourself.
/// ///
/// This will read randomness from the operating system to seed the /// This will seed the generator with randomness from thread_rng.
/// generator. #[cfg(feature="std")]
pub fn weak_rng() -> XorShiftRng { pub fn weak_rng() -> XorShiftRng {
match OsRng::new() { thread_rng().gen()
Ok(mut r) => r.gen(),
Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
}
} }
/// Controls how the thread-local RNG is reseeded. /// Controls how the thread-local RNG is reseeded.
#[cfg(feature="std")]
#[derive(Debug)] #[derive(Debug)]
struct ThreadRngReseeder; struct ThreadRngReseeder;
#[cfg(feature="std")]
impl reseeding::Reseeder<StdRng> for ThreadRngReseeder { impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
fn reseed(&mut self, rng: &mut StdRng) { fn reseed(&mut self, rng: &mut StdRng) {
*rng = match StdRng::new() { match StdRng::new() {
Ok(r) => r, Ok(r) => *rng = r,
Err(e) => panic!("could not reseed thread_rng: {}", e) Err(e) => panic!("No entropy available: {}", e),
} }
} }
} }
#[cfg(feature="std")]
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768;
#[cfg(feature="std")]
type ThreadRngInner = reseeding::ReseedingRng<StdRng, ThreadRngReseeder>; type ThreadRngInner = reseeding::ReseedingRng<StdRng, ThreadRngReseeder>;
/// The thread-local RNG. /// The thread-local RNG.
#[cfg(feature="std")]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ThreadRng { pub struct ThreadRng {
rng: Rc<RefCell<ThreadRngInner>>, rng: Rc<RefCell<ThreadRngInner>>,
@ -925,19 +864,21 @@ pub struct ThreadRng {
/// generator, seeded by the system. Intended to be used in method /// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`. /// chaining style, e.g. `thread_rng().gen::<i32>()`.
/// ///
/// The RNG provided will reseed itself from the operating system /// After generating a certain amount of randomness, the RNG will reseed itself
/// after generating a certain amount of randomness. /// from the operating system or, if the operating system RNG returns an error,
/// a seed based on the current system time.
/// ///
/// The internal RNG used is platform and architecture dependent, even /// The internal RNG used is platform and architecture dependent, even
/// if the operating system random number generator is rigged to give /// if the operating system random number generator is rigged to give
/// the same sequence always. If absolute consistency is required, /// the same sequence always. If absolute consistency is required,
/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
#[cfg(feature="std")]
pub fn thread_rng() -> ThreadRng { pub fn thread_rng() -> ThreadRng {
// used to make space in TLS for a random number generator // used to make space in TLS for a random number generator
thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = { thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = {
let r = match StdRng::new() { let r = match StdRng::new() {
Ok(r) => r, Ok(r) => r,
Err(e) => panic!("could not initialize thread_rng: {}", e) Err(e) => panic!("No entropy available: {}", e),
}; };
let rng = reseeding::ReseedingRng::new(r, let rng = reseeding::ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD, THREAD_RNG_RESEED_THRESHOLD,
@ -948,6 +889,7 @@ pub fn thread_rng() -> ThreadRng {
ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
} }
#[cfg(feature="std")]
impl Rng for ThreadRng { impl Rng for ThreadRng {
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
self.rng.borrow_mut().next_u32() self.rng.borrow_mut().next_u32()
@ -997,7 +939,7 @@ impl Rng for ThreadRng {
/// *x = rand::random() /// *x = rand::random()
/// } /// }
/// ///
/// // would be faster as /// // can be made faster by caching thread_rng
/// ///
/// let mut rng = rand::thread_rng(); /// let mut rng = rand::thread_rng();
/// ///
@ -1005,11 +947,14 @@ impl Rng for ThreadRng {
/// *x = rng.gen(); /// *x = rng.gen();
/// } /// }
/// ``` /// ```
#[cfg(feature="std")]
#[inline] #[inline]
pub fn random<T: Rand>() -> T { pub fn random<T: Rand>() -> T {
thread_rng().gen() thread_rng().gen()
} }
/// DEPRECATED: use `seq::sample_iter` instead.
///
/// Randomly sample up to `amount` elements from a finite iterator. /// Randomly sample up to `amount` elements from a finite iterator.
/// The order of elements in the sample is not random. /// The order of elements in the sample is not random.
/// ///
@ -1022,37 +967,35 @@ pub fn random<T: Rand>() -> T {
/// let sample = sample(&mut rng, 1..100, 5); /// let sample = sample(&mut rng, 1..100, 5);
/// println!("{:?}", sample); /// println!("{:?}", sample);
/// ``` /// ```
#[cfg(feature="std")]
#[inline(always)]
#[deprecated(since="0.4.0", note="renamed to seq::sample_iter")]
pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T> pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
where I: IntoIterator<Item=T>, where I: IntoIterator<Item=T>,
R: Rng, R: Rng,
{ {
let mut iter = iterable.into_iter(); // the legacy sample didn't care whether amount was met
let mut reservoir: Vec<T> = iter.by_ref().take(amount).collect(); seq::sample_iter(rng, iterable, amount)
// continue unless the iterator was exhausted .unwrap_or_else(|e| e)
if reservoir.len() == amount {
for (i, elem) in iter.enumerate() {
let k = rng.gen_range(0, i + 1 + amount);
if let Some(spot) = reservoir.get_mut(k) {
*spot = elem;
}
}
}
reservoir
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample}; use impls;
use super::{Rng, thread_rng, random, SeedableRng, StdRng, weak_rng};
use std::iter::repeat; use std::iter::repeat;
pub struct MyRng<R> { inner: R } pub struct MyRng<R> { inner: R }
impl<R: Rng> Rng for MyRng<R> { impl<R: Rng> Rng for MyRng<R> {
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
fn next<T: Rng>(t: &mut T) -> u32 { self.inner.next_u32()
t.next_u32() }
} fn next_u64(&mut self) -> u64 {
next(&mut self.inner) self.inner.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.inner.fill_bytes(dest)
} }
} }
@ -1065,7 +1008,9 @@ mod test {
fn next_u32(&mut self) -> u32 { self.i as u32 } fn next_u32(&mut self) -> u32 { self.i as u32 }
fn next_u64(&mut self) -> u64 { self.i } fn next_u64(&mut self) -> u64 { self.i }
// no fill_bytes on purpose fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u64(self, dest)
}
} }
pub fn iter_eq<I, J>(i: I, j: J) -> bool pub fn iter_eq<I, J>(i: I, j: J) -> bool
@ -1138,14 +1083,6 @@ mod test {
r.gen_range(5, 2); r.gen_range(5, 2);
} }
#[test]
fn test_gen_f64() {
let mut r = thread_rng();
let a = r.gen::<f64>();
let b = r.gen::<f64>();
debug!("{:?}", (a, b));
}
#[test] #[test]
fn test_gen_weighted_bool() { fn test_gen_weighted_bool() {
let mut r = thread_rng(); let mut r = thread_rng();
@ -1248,24 +1185,6 @@ mod test {
(f32, (f64, (f64,)))) = random(); (f32, (f64, (f64,)))) = random();
} }
#[test]
fn test_sample() {
let min_val = 1;
let max_val = 100;
let mut r = thread_rng();
let vals = (min_val..max_val).collect::<Vec<i32>>();
let small_sample = sample(&mut r, vals.iter(), 5);
let large_sample = sample(&mut r, vals.iter(), vals.len() + 5);
assert_eq!(small_sample.len(), 5);
assert_eq!(large_sample.len(), vals.len());
assert!(small_sample.iter().all(|e| {
**e >= min_val && **e <= max_val
}));
}
#[test] #[test]
fn test_std_rng_seeded() { fn test_std_rng_seeded() {
let s = thread_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>(); let s = thread_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
@ -1286,4 +1205,13 @@ mod test {
let string2 = r.gen_ascii_chars().take(100).collect::<String>(); let string2 = r.gen_ascii_chars().take(100).collect::<String>();
assert_eq!(string1, string2); assert_eq!(string1, string2);
} }
#[test]
fn test_weak_rng() {
let s = weak_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
let mut ra: StdRng = SeedableRng::from_seed(&s[..]);
let mut rb: StdRng = SeedableRng::from_seed(&s[..]);
assert!(iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
} }

View File

@ -53,13 +53,13 @@ impl fmt::Debug for OsRng {
} }
} }
fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 { fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 {
let mut buf: [u8; 4] = [0; 4]; let mut buf: [u8; 4] = [0; 4];
fill_buf(&mut buf); fill_buf(&mut buf);
unsafe { mem::transmute::<[u8; 4], u32>(buf) } unsafe { mem::transmute::<[u8; 4], u32>(buf) }
} }
fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 {
let mut buf: [u8; 8] = [0; 8]; let mut buf: [u8; 8] = [0; 8];
fill_buf(&mut buf); fill_buf(&mut buf);
unsafe { mem::transmute::<[u8; 8], u64>(buf) } unsafe { mem::transmute::<[u8; 8], u64>(buf) }
@ -407,7 +407,7 @@ mod imp {
next_u64(&mut |v| self.fill_bytes(v)) next_u64(&mut |v| self.fill_bytes(v))
} }
fn fill_bytes(&mut self, v: &mut [u8]) { fn fill_bytes(&mut self, v: &mut [u8]) {
for s in v.chunks_mut(fuchsia_zircon::ZX_CPRNG_DRAW_MAX_LEN) { for s in v.chunks_mut(fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN) {
let mut filled = 0; let mut filled = 0;
while filled < s.len() { while filled < s.len() {
match fuchsia_zircon::cprng_draw(&mut s[filled..]) { match fuchsia_zircon::cprng_draw(&mut s[filled..]) {
@ -422,19 +422,16 @@ mod imp {
#[cfg(windows)] #[cfg(windows)]
mod imp { mod imp {
extern crate winapi;
use std::io; use std::io;
use Rng; use Rng;
use super::{next_u32, next_u64}; use super::{next_u32, next_u64};
type BOOLEAN = u8; use self::winapi::shared::minwindef::ULONG;
type ULONG = u32; use self::winapi::um::ntsecapi::RtlGenRandom;
use self::winapi::um::winnt::PVOID;
#[link(name = "advapi32")]
extern "system" {
// This function's real name is `RtlGenRandom`.
fn SystemFunction036(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
}
#[derive(Debug)] #[derive(Debug)]
pub struct OsRng; pub struct OsRng;
@ -457,7 +454,7 @@ mod imp {
// split up the buffer. // split up the buffer.
for slice in v.chunks_mut(<ULONG>::max_value() as usize) { for slice in v.chunks_mut(<ULONG>::max_value() as usize) {
let ret = unsafe { let ret = unsafe {
SystemFunction036(slice.as_mut_ptr(), slice.len() as ULONG) RtlGenRandom(slice.as_mut_ptr() as PVOID, slice.len() as ULONG)
}; };
if ret == 0 { if ret == 0 {
panic!("couldn't generate random bytes: {}", panic!("couldn't generate random bytes: {}",
@ -544,6 +541,26 @@ mod imp {
} }
} }
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod imp {
use std::io;
use Rng;
#[derive(Debug)]
pub struct OsRng;
impl OsRng {
pub fn new() -> io::Result<OsRng> {
Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
}
}
impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
panic!("Not supported")
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View File

@ -10,8 +10,9 @@
//! The ChaCha random number generator. //! The ChaCha random number generator.
use std::num::Wrapping as w; use core::fmt;
use {Rng, SeedableRng, Rand, w32}; use {Rng, SeedableRng, Rand};
use impls;
const KEY_WORDS : usize = 8; // 8 words for the 256-bit key const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
const STATE_WORDS : usize = 16; const STATE_WORDS : usize = 16;
@ -26,26 +27,26 @@ const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of
/// ///
/// [1]: D. J. Bernstein, [*ChaCha, a variant of /// [1]: D. J. Bernstein, [*ChaCha, a variant of
/// Salsa20*](https://cr.yp.to/chacha.html) /// Salsa20*](https://cr.yp.to/chacha.html)
#[derive(Copy, Clone, Debug)] #[derive(Clone)]
pub struct ChaChaRng { pub struct ChaChaRng {
buffer: [w32; STATE_WORDS], // Internal buffer of output buffer: [u32; STATE_WORDS], // Internal buffer of output
state: [w32; STATE_WORDS], // Initial state state: [u32; STATE_WORDS], // Initial state
index: usize, // Index into state index: usize, // Index into state
} }
static EMPTY: ChaChaRng = ChaChaRng { // Custom Debug implementation that does not expose the internal state
buffer: [w(0); STATE_WORDS], impl fmt::Debug for ChaChaRng {
state: [w(0); STATE_WORDS], fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
index: STATE_WORDS write!(f, "ChaChaRng {{}}")
}; }
}
macro_rules! quarter_round{ macro_rules! quarter_round{
($a: expr, $b: expr, $c: expr, $d: expr) => {{ ($a: expr, $b: expr, $c: expr, $d: expr) => {{
$a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left(16)); $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left(16);
$c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left(12)); $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left(12);
$a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left( 8)); $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left( 8);
$c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left( 7)); $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left( 7);
}} }}
} }
@ -65,15 +66,15 @@ macro_rules! double_round{
} }
#[inline] #[inline]
fn core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS]) { fn core(new: &mut [u32; STATE_WORDS], input: &[u32; STATE_WORDS]) {
*output = *input; *new = *input;
for _ in 0..CHACHA_ROUNDS / 2 { for _ in 0..CHACHA_ROUNDS / 2 {
double_round!(output); double_round!(new);
} }
for i in 0..STATE_WORDS { for i in 0..STATE_WORDS {
output[i] = output[i] + input[i]; new[i] = new[i].wrapping_add(input[i]);
} }
} }
@ -99,7 +100,11 @@ impl ChaChaRng {
/// - 2917185654 /// - 2917185654
/// - 2419978656 /// - 2419978656
pub fn new_unseeded() -> ChaChaRng { pub fn new_unseeded() -> ChaChaRng {
let mut rng = EMPTY; let mut rng = ChaChaRng {
buffer: [0; STATE_WORDS],
state: [0; STATE_WORDS],
index: STATE_WORDS
};
rng.init(&[0; KEY_WORDS]); rng.init(&[0; KEY_WORDS]);
rng rng
} }
@ -124,10 +129,10 @@ impl ChaChaRng {
/// println!("{:?}", ra.next_u32()); /// println!("{:?}", ra.next_u32());
/// ``` /// ```
pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) { pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
self.state[12] = w((counter_low >> 0) as u32); self.state[12] = (counter_low >> 0) as u32;
self.state[13] = w((counter_low >> 32) as u32); self.state[13] = (counter_low >> 32) as u32;
self.state[14] = w((counter_high >> 0) as u32); self.state[14] = (counter_high >> 0) as u32;
self.state[15] = w((counter_high >> 32) as u32); self.state[15] = (counter_high >> 32) as u32;
self.index = STATE_WORDS; // force recomputation self.index = STATE_WORDS; // force recomputation
} }
@ -150,19 +155,19 @@ impl ChaChaRng {
/// [1]: Daniel J. Bernstein. [*Extending the Salsa20 /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
/// nonce.*](https://cr.yp.to/papers.html#xsalsa) /// nonce.*](https://cr.yp.to/papers.html#xsalsa)
fn init(&mut self, key: &[u32; KEY_WORDS]) { fn init(&mut self, key: &[u32; KEY_WORDS]) {
self.state[0] = w(0x61707865); self.state[0] = 0x61707865;
self.state[1] = w(0x3320646E); self.state[1] = 0x3320646E;
self.state[2] = w(0x79622D32); self.state[2] = 0x79622D32;
self.state[3] = w(0x6B206574); self.state[3] = 0x6B206574;
for i in 0..KEY_WORDS { for i in 0..KEY_WORDS {
self.state[4+i] = w(key[i]); self.state[4+i] = key[i];
} }
self.state[12] = w(0); self.state[12] = 0;
self.state[13] = w(0); self.state[13] = 0;
self.state[14] = w(0); self.state[14] = 0;
self.state[15] = w(0); self.state[15] = 0;
self.index = STATE_WORDS; self.index = STATE_WORDS;
} }
@ -172,39 +177,46 @@ impl ChaChaRng {
core(&mut self.buffer, &self.state); core(&mut self.buffer, &self.state);
self.index = 0; self.index = 0;
// update 128-bit counter // update 128-bit counter
self.state[12] = self.state[12] + w(1); self.state[12] = self.state[12].wrapping_add(1);
if self.state[12] != w(0) { return }; if self.state[12] != 0 { return };
self.state[13] = self.state[13] + w(1); self.state[13] = self.state[13].wrapping_add(1);
if self.state[13] != w(0) { return }; if self.state[13] != 0 { return };
self.state[14] = self.state[14] + w(1); self.state[14] = self.state[14].wrapping_add(1);
if self.state[14] != w(0) { return }; if self.state[14] != 0 { return };
self.state[15] = self.state[15] + w(1); self.state[15] = self.state[15].wrapping_add(1);
} }
} }
impl Rng for ChaChaRng { impl Rng for ChaChaRng {
#[inline] #[inline]
fn next_u32(&mut self) -> u32 { fn next_u32(&mut self) -> u32 {
if self.index == STATE_WORDS { // Using a local variable for `index`, and checking the size avoids a
// bounds check later on.
let mut index = self.index as usize;
if index >= STATE_WORDS {
self.update(); self.update();
index = 0;
} }
let value = self.buffer[self.index % STATE_WORDS]; let value = self.buffer[index];
self.index += 1; self.index += 1;
value.0 value
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, bytes: &mut [u8]) {
impls::fill_bytes_via_u32(self, bytes)
} }
} }
impl<'a> SeedableRng<&'a [u32]> for ChaChaRng { impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
fn reseed(&mut self, seed: &'a [u32]) { fn reseed(&mut self, seed: &'a [u32]) {
// reset state *self = Self::from_seed(seed);
self.init(&[0u32; KEY_WORDS]);
// set key in place
let key = &mut self.state[4 .. 4+KEY_WORDS];
for (k, s) in key.iter_mut().zip(seed.iter()) {
*k = w(*s);
}
} }
/// Create a ChaCha generator from a seed, /// Create a ChaCha generator from a seed,
@ -212,8 +224,19 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
/// Only up to 8 words are used; if less than 8 /// Only up to 8 words are used; if less than 8
/// words are used, the remaining are set to zero. /// words are used, the remaining are set to zero.
fn from_seed(seed: &'a [u32]) -> ChaChaRng { fn from_seed(seed: &'a [u32]) -> ChaChaRng {
let mut rng = EMPTY; let mut rng = ChaChaRng {
rng.reseed(seed); buffer: [0; STATE_WORDS],
state: [0; STATE_WORDS],
index: STATE_WORDS
};
rng.init(&[0u32; KEY_WORDS]);
// set key in place
{
let key = &mut rng.state[4 .. 4+KEY_WORDS];
for (k, s) in key.iter_mut().zip(seed.iter()) {
*k = *s;
}
}
rng rng
} }
} }
@ -306,6 +329,20 @@ mod test {
0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4)); 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
} }
#[test]
fn test_rng_true_bytes() {
let seed : &[_] = &[0u32; 8];
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
let mut buf = [0u8; 32];
ra.fill_bytes(&mut buf);
// Same as first values in test_isaac_true_values as bytes in LE order
assert_eq!(buf,
[118, 184, 224, 173, 160, 241, 61, 144,
64, 93, 106, 229, 83, 134, 189, 40,
189, 210, 25, 184, 160, 141, 237, 26,
168, 54, 239, 204, 139, 119, 13, 199]);
}
#[test] #[test]
fn test_rng_clone() { fn test_rng_clone() {
let seed : &[_] = &[0u32; 8]; let seed : &[_] = &[0u32; 8];

471
src/prng/isaac.rs Normal file
View File

@ -0,0 +1,471 @@
// Copyright 2013 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.
//! The ISAAC random number generator.
use core::slice;
use core::iter::repeat;
use core::num::Wrapping as w;
use core::fmt;
use {Rng, SeedableRng, Rand};
use impls;
#[allow(non_camel_case_types)]
type w32 = w<u32>;
const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// A random number generator that uses the ISAAC algorithm.
///
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
/// the principal bitwise operations employed. It is the most advanced of a
/// series of array based random number generator designed by Robert Jenkins
/// in 1996[1][2].
///
/// Although ISAAC is designed to be cryptographically secure, its design is not
/// founded in cryptographic theory. Therefore it is _not recommended for_
/// cryptographic purposes. It is however one of the strongest non-cryptograpic
/// RNGs, and that while still being reasonably fast.
///
/// Where fast random numbers are needed which should still be secure, but where
/// speed is more important than absolute (cryptographic) security (e.g. to
/// initialise hashes in the std library), a generator like ISAAC may be a good
/// choice.
///
/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
/// named ISAAC+[3]. But because the specification is not complete, there is no
/// good implementation, and because the suggested bias may not exist, it is not
/// implemented here.
///
/// ## Overview of the ISAAC algorithm:
/// (in pseudo-code)
///
/// ```text
/// Input: a, b, c, s[256] // state
/// Output: r[256] // results
///
/// mix(a,i) = a ^ a << 13 if i = 0 mod 4
/// a ^ a >> 6 if i = 1 mod 4
/// a ^ a << 2 if i = 2 mod 4
/// a ^ a >> 16 if i = 3 mod 4
///
/// c = c + 1
/// b = b + c
///
/// for i in 0..256 {
/// x = s_[i]
/// a = f(a,i) + s[i+128 mod 256]
/// y = a + b + s[x>>2 mod 256]
/// s[i] = y
/// b = x + s[y>>10 mod 256]
/// r[i] = b
/// }
/// ```
///
/// Numbers are generated in blocks of 256. This means the function above only
/// runs once every 256 times you ask for a next random number. In all other
/// circumstances the last element of the results array is returned.
///
/// ISAAC therefore needs a lot of memory, relative to other non-vrypto RNGs.
/// 2 * 256 * 4 = 2 kb to hold the state and results.
///
/// ## References
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*]
/// (http://burtleburtle.net/bob/rand/isaacafa.html)
///
/// [2]: Bob Jenkins, [*ISAAC and RC4*]
/// (http://burtleburtle.net/bob/rand/isaac.html)
///
/// [3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]
/// (http://eprint.iacr.org/2006/438)
pub struct IsaacRng {
rsl: [u32; RAND_SIZE],
mem: [w32; RAND_SIZE],
a: w32,
b: w32,
c: w32,
index: u32,
}
// Cannot be derived because [u32; 256] does not implement Clone
// FIXME: remove once RFC 2000 gets implemented
impl Clone for IsaacRng {
fn clone(&self) -> IsaacRng {
IsaacRng {
rsl: self.rsl,
mem: self.mem,
a: self.a,
b: self.b,
c: self.c,
index: self.index,
}
}
}
// Custom Debug implementation that does not expose the internal state
impl fmt::Debug for IsaacRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IsaacRng {{}}")
}
}
impl IsaacRng {
/// Create an ISAAC random number generator using the default
/// fixed seed.
pub fn new_unseeded() -> IsaacRng {
Self::new_from_u64(0)
}
/// Creates an ISAAC random number generator using an u64 as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
pub fn new_from_u64(seed: u64) -> IsaacRng {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed as u32);
key[1] = w((seed >> 32) as u32);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of
// the seed was already available in the first round.
// Not doing the second pass has the small advantage that if `seed == 0`
// this method produces exactly the same state as the reference
// implementation when used unseeded.
init(key, 1)
}
/// Refills the output buffer (`self.rsl`)
/// See also the pseudocode desciption of the algorithm at the top of this
/// file.
///
/// Optimisations used (similar to the reference implementation):
/// - The loop is unrolled 4 times, once for every constant of mix().
/// - The contents of the main loop are moved to a function `rngstep`, to
/// reduce code duplication.
/// - We use local variables for a and b, which helps with optimisations.
/// - We split the main loop in two, one that operates over 0..128 and one
/// over 128..256. This way we can optimise out the addition and modulus
/// from `s[i+128 mod 256]`.
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
/// arithmetic.
/// - We fill `rsl` backwards. The reference implementation reads values
/// from `rsl` in reverse. We read them in the normal direction, to make
/// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
fn isaac(&mut self) {
self.c += w(1);
// abbreviations
let mut a = self.a;
let mut b = self.b + self.c;
const MIDPOINT: usize = RAND_SIZE / 2;
#[inline]
fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 {
let index = (v >> amount).0 as usize % RAND_SIZE;
mem[index]
}
#[inline]
fn rngstep(ctx: &mut IsaacRng,
mix: w32,
a: &mut w32,
b: &mut w32,
base: usize,
m: usize,
m2: usize) {
let x = ctx.mem[base + m];
*a = mix + ctx.mem[base + m2];
let y = *a + *b + ind(&ctx.mem, x, 2);
ctx.mem[base + m] = y;
*b = x + ind(&ctx.mem, y, 2 + RAND_SIZE_LEN);
ctx.rsl[RAND_SIZE - 1 - base - m] = (*b).0;
}
let mut m = 0;
let mut m2 = MIDPOINT;
for i in (0..MIDPOINT/4).map(|i| i * 4) {
rngstep(self, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
rngstep(self, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
rngstep(self, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
rngstep(self, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
}
m = MIDPOINT;
m2 = 0;
for i in (0..MIDPOINT/4).map(|i| i * 4) {
rngstep(self, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
rngstep(self, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
rngstep(self, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
rngstep(self, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
}
self.a = a;
self.b = b;
self.index = 0;
}
}
impl Rng for IsaacRng {
#[inline]
fn next_u32(&mut self) -> u32 {
// Using a local variable for `index`, and checking the size avoids a
// bounds check later on.
let mut index = self.index as usize;
if index >= RAND_SIZE {
self.isaac();
index = 0;
}
let value = self.rsl[index];
self.index += 1;
value
}
#[inline]
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
while read_len < dest.len() {
if self.index as usize >= RAND_SIZE {
self.isaac();
}
let (consumed_u32, filled_u8) =
impls::fill_via_u32_chunks(&mut self.rsl[(self.index as usize)..],
&mut dest[read_len..]);
self.index += consumed_u32 as u32;
read_len += filled_u8;
}
}
}
/// Creates a new ISAAC random number generator.
///
/// The author Bob Jenkins describes how to best initialize ISAAC here:
/// https://rt.cpan.org/Public/Bug/Display.html?id=64324
/// The answer is included here just in case:
///
/// "No, you don't need a full 8192 bits of seed data. Normal key sizes will do
/// fine, and they should have their expected strength (eg a 40-bit key will
/// take as much time to brute force as 40-bit keys usually will). You could
/// fill the remainder with 0, but set the last array element to the length of
/// the key provided (to distinguish keys that differ only by different amounts
/// of 0 padding). You do still need to call randinit() to make sure the initial
/// state isn't uniform-looking."
/// "After publishing ISAAC, I wanted to limit the key to half the size of r[],
/// and repeat it twice. That would have made it hard to provide a key that sets
/// the whole internal state to anything convenient. But I'd already published
/// it."
///
/// And his answer to the question "For my code, would repeating the key over
/// and over to fill 256 integers be a better solution than zero-filling, or
/// would they essentially be the same?":
/// "If the seed is under 32 bytes, they're essentially the same, otherwise
/// repeating the seed would be stronger. randinit() takes a chunk of 32 bytes,
/// mixes it, and combines that with the next 32 bytes, et cetera. Then loops
/// over all the elements the same way a second time."
#[inline]
fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> IsaacRng {
// These numbers are the result of initializing a...h with the
// fractional part of the golden ratio in binary (0x9e3779b9)
// and applying mix() 4 times.
let mut a = w(0x1367df5a);
let mut b = w(0x95d90059);
let mut c = w(0xc3163e4b);
let mut d = w(0x0f421ad8);
let mut e = w(0xd92a4a78);
let mut f = w(0xa51a3c49);
let mut g = w(0xc4efea1b);
let mut h = w(0x30609119);
// Normally this should do two passes, to make all of the seed effect all
// of `mem`
for _ in 0..rounds {
for i in (0..RAND_SIZE/8).map(|i| i * 8) {
a += mem[i ]; b += mem[i+1];
c += mem[i+2]; d += mem[i+3];
e += mem[i+4]; f += mem[i+5];
g += mem[i+6]; h += mem[i+7];
mix(&mut a, &mut b, &mut c, &mut d,
&mut e, &mut f, &mut g, &mut h);
mem[i ] = a; mem[i+1] = b;
mem[i+2] = c; mem[i+3] = d;
mem[i+4] = e; mem[i+5] = f;
mem[i+6] = g; mem[i+7] = h;
}
}
let mut rng = IsaacRng {
rsl: [0; RAND_SIZE],
mem: mem,
a: w(0),
b: w(0),
c: w(0),
index: 0,
};
// Prepare the first set of results
rng.isaac();
rng
}
fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32,
e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) {
*a ^= *b << 11; *d += *a; *b += *c;
*b ^= *c >> 2; *e += *b; *c += *d;
*c ^= *d << 8; *f += *c; *d += *e;
*d ^= *e >> 16; *g += *d; *e += *f;
*e ^= *f << 10; *h += *e; *f += *g;
*f ^= *g >> 4; *a += *f; *g += *h;
*g ^= *h << 8; *b += *g; *h += *a;
*h ^= *a >> 9; *c += *h; *a += *b;
}
impl Rand for IsaacRng {
fn rand<R: Rng>(other: &mut R) -> IsaacRng {
let mut key = [w(0); RAND_SIZE];
unsafe {
let ptr = key.as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4);
other.fill_bytes(slice);
}
init(key, 2)
}
}
impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
fn reseed(&mut self, seed: &'a [u32]) {
*self = Self::from_seed(seed);
}
/// Create an ISAAC random number generator with a seed. This can
/// be any length, although the maximum number of elements used is
/// 256 and any more will be silently ignored. A generator
/// constructed with a given seed will generate the same sequence
/// of values as all other generators constructed with that seed.
fn from_seed(seed: &'a [u32]) -> IsaacRng {
let mut key = [w(0); RAND_SIZE];
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
// - 1], 0, 0, ...], to fill `key`.
let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u32));
for (rsl_elem, seed_elem) in key.iter_mut().zip(seed_iter) {
*rsl_elem = w(seed_elem);
}
init(key, 2)
}
}
#[cfg(test)]
mod test {
use {Rng, SeedableRng};
use super::IsaacRng;
#[test]
fn test_rng_32_rand_seeded() {
let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
let mut ra: IsaacRng = SeedableRng::from_seed(&s[..]);
let mut rb: IsaacRng = SeedableRng::from_seed(&s[..]);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_32_seeded() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_32_reseed() {
let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
let mut r: IsaacRng = SeedableRng::from_seed(&s[..]);
let string1: String = r.gen_ascii_chars().take(100).collect();
r.reseed(&s[..]);
let string2: String = r.gen_ascii_chars().take(100).collect();
assert_eq!(string1, string2);
}
#[test]
fn test_rng_32_true_values() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = (0..10).map(|_| ra.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709,
4203127393, 264982119, 2765226902, 2737944514, 3900253796));
let seed: &[_] = &[12345, 67890, 54321, 9876];
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
for _ in 0..10000 { rb.next_u32(); }
let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
vec!(3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
1576568959, 3507990155, 179069555, 141456972, 2478885421));
}
#[test]
fn test_rng_64_true_values() {
// As above, using little-endian versions of above values
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = (0..5).map(|_| ra.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
vec!(3752888579798383186, 9035083239252078381, 18052294697452424037, 11876559110374379111, 16751462502657800130));
}
#[test]
fn test_isaac_true_bytes() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut rng1 = IsaacRng::from_seed(seed);
let mut buf = [0u8; 32];
rng1.fill_bytes(&mut buf);
// Same as first values in test_isaac_true_values as bytes in LE order
assert_eq!(buf,
[82, 186, 128, 152, 71, 240, 20, 52,
45, 175, 180, 15, 86, 16, 99, 125,
101, 203, 81, 214, 97, 162, 134, 250,
103, 78, 203, 15, 150, 3, 210, 164]);
}
#[test]
fn test_isaac_new_uninitialized() {
// Compare the results from initializing `IsaacRng` with
// `new_from_u64(0)`, to make sure it is the same as the reference
// implementation when used uninitialized.
// Note: We only test the first 16 integers, not the full 256 of the
// first block.
let mut rng = IsaacRng::new_from_u64(0);
let vec = (0..16).map(|_| rng.next_u32()).collect::<Vec<_>>();
let expected: [u32; 16] = [
0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA,
0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD,
0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846,
0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F];
assert_eq!(vec, expected);
}
}

487
src/prng/isaac64.rs Normal file
View File

@ -0,0 +1,487 @@
// Copyright 2013 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.
//! The ISAAC-64 random number generator.
use core::slice;
use core::iter::repeat;
use core::num::Wrapping as w;
use core::fmt;
use {Rng, SeedableRng, Rand};
use impls;
#[allow(non_camel_case_types)]
type w64 = w<u64>;
const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// A random number generator that uses ISAAC-64, the 64-bit variant of the
/// ISAAC algorithm.
///
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
/// the principal bitwise operations employed. It is the most advanced of a
/// series of array based random number generator designed by Robert Jenkins
/// in 1996[1].
///
/// Although ISAAC is designed to be cryptographically secure, its design is not
/// founded in cryptographic theory. Therefore it is _not recommended for_
/// cryptographic purposes. It is however one of the strongest non-cryptograpic
/// RNGs, and that while still being reasonably fast.
///
/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
/// instead of 32-bit, it uses twice as much memory to hold its state and
/// results. Also it uses different constants for shifts and indirect indexing,
/// optimized to give good results for 64bit arithmetic.
///
/// ## Overview of the ISAAC-64 algorithm:
/// (in pseudo-code)
///
/// ```text
/// Input: a, b, c, s[256] // state
/// Output: r[256] // results
///
/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4
/// a ^ a >> 5 if i = 1 mod 4
/// a ^ a << 12 if i = 2 mod 4
/// a ^ a >> 33 if i = 3 mod 4
///
/// c = c + 1
/// b = b + c
///
/// for i in 0..256 {
/// x = s_[i]
/// a = mix(a,i) + s[i+128 mod 256]
/// y = a + b + s[x>>3 mod 256]
/// s[i] = y
/// b = x + s[y>>11 mod 256]
/// r[i] = b
/// }
/// ```
///
/// See for more information the description in rand::prng::IsaacRng.
///
/// [1]: Bob Jenkins, [*ISAAC and RC4*]
/// (http://burtleburtle.net/bob/rand/isaac.html)
pub struct Isaac64Rng {
rsl: [u64; RAND_SIZE],
mem: [w64; RAND_SIZE],
a: w64,
b: w64,
c: w64,
index: u32,
half_used: bool, // true if only half of the previous result is used
}
// Cannot be derived because [u64; 256] does not implement Clone
// FIXME: remove once RFC 2000 gets implemented
impl Clone for Isaac64Rng {
fn clone(&self) -> Isaac64Rng {
Isaac64Rng {
rsl: self.rsl,
mem: self.mem,
a: self.a,
b: self.b,
c: self.c,
index: self.index,
half_used: self.half_used,
}
}
}
// Custom Debug implementation that does not expose the internal state
impl fmt::Debug for Isaac64Rng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Isaac64Rng {{}}")
}
}
impl Isaac64Rng {
/// Create a 64-bit ISAAC random number generator using the
/// default fixed seed.
pub fn new_unseeded() -> Isaac64Rng {
Self::new_from_u64(0)
}
/// Creates an ISAAC-64 random number generator using an u64 as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
pub fn new_from_u64(seed: u64) -> Isaac64Rng {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of
// the seed was already available in the first round.
// Not doing the second pass has the small advantage that if `seed == 0`
// this method produces exactly the same state as the reference
// implementation when used unseeded.
init(key, 1)
}
/// Refills the output buffer (`self.rsl`)
/// See also the pseudocode desciption of the algorithm at the top of this
/// file.
///
/// Optimisations used (similar to the reference implementation):
/// - The loop is unrolled 4 times, once for every constant of mix().
/// - The contents of the main loop are moved to a function `rngstep`, to
/// reduce code duplication.
/// - We use local variables for a and b, which helps with optimisations.
/// - We split the main loop in two, one that operates over 0..128 and one
/// over 128..256. This way we can optimise out the addition and modulus
/// from `s[i+128 mod 256]`.
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
/// arithmetic.
/// - We fill `rsl` backwards. The reference implementation reads values
/// from `rsl` in reverse. We read them in the normal direction, to make
/// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
fn isaac64(&mut self) {
self.c += w(1);
// abbreviations
let mut a = self.a;
let mut b = self.b + self.c;
const MIDPOINT: usize = RAND_SIZE / 2;
#[inline]
fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 {
let index = (v >> amount).0 as usize % RAND_SIZE;
mem[index]
}
#[inline]
fn rngstep(ctx: &mut Isaac64Rng,
mix: w64,
a: &mut w64,
b: &mut w64,
base: usize,
m: usize,
m2: usize) {
let x = ctx.mem[base + m];
*a = mix + ctx.mem[base + m2];
let y = *a + *b + ind(&ctx.mem, x, 3);
ctx.mem[base + m] = y;
*b = x + ind(&ctx.mem, y, 3 + RAND_SIZE_LEN);
ctx.rsl[RAND_SIZE - 1 - base - m] = (*b).0;
}
let mut m = 0;
let mut m2 = MIDPOINT;
for i in (0..MIDPOINT/4).map(|i| i * 4) {
rngstep(self, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
rngstep(self, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2);
rngstep(self, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2);
rngstep(self, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2);
}
m = MIDPOINT;
m2 = 0;
for i in (0..MIDPOINT/4).map(|i| i * 4) {
rngstep(self, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
rngstep(self, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2);
rngstep(self, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2);
rngstep(self, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2);
}
self.a = a;
self.b = b;
self.index = 0;
self.half_used = false;
}
}
impl Rng for Isaac64Rng {
#[inline]
fn next_u32(&mut self) -> u32 {
// Using a local variable for `index`, and checking the size avoids a
// bounds check later on.
let mut index = self.index as usize * 2 - self.half_used as usize;
if index >= RAND_SIZE * 2 {
self.isaac64();
index = 0;
}
self.half_used = !self.half_used;
self.index += self.half_used as u32;
// Index as if this is a u32 slice.
let rsl = unsafe { &*(&mut self.rsl as *mut [u64; RAND_SIZE]
as *mut [u32; RAND_SIZE * 2]) };
if cfg!(target_endian = "little") {
rsl[index]
} else {
rsl[index ^ 1]
}
}
#[inline]
fn next_u64(&mut self) -> u64 {
let mut index = self.index as usize;
if index >= RAND_SIZE {
self.isaac64();
index = 0;
}
let value = self.rsl[index];
self.index += 1;
self.half_used = false;
value
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
while read_len < dest.len() {
if self.index as usize >= RAND_SIZE {
self.isaac64();
}
let (consumed_u64, filled_u8) =
impls::fill_via_u64_chunks(&mut self.rsl[self.index as usize..],
&mut dest[read_len..]);
self.index += consumed_u64 as u32;
read_len += filled_u8;
}
}
}
/// Creates a new ISAAC-64 random number generator.
fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Isaac64Rng {
// These numbers are the result of initializing a...h with the
// fractional part of the golden ratio in binary (0x9e3779b97f4a7c13)
// and applying mix() 4 times.
let mut a = w(0x647c4677a2884b7c);
let mut b = w(0xb9f8b322c73ac862);
let mut c = w(0x8c0ea5053d4712a0);
let mut d = w(0xb29b2e824a595524);
let mut e = w(0x82f053db8355e0ce);
let mut f = w(0x48fe4a0fa5a09315);
let mut g = w(0xae985bf2cbfc89ed);
let mut h = w(0x98f5704f6c44c0ab);
// Normally this should do two passes, to make all of the seed effect all
// of `mem`
for _ in 0..rounds {
for i in (0..RAND_SIZE/8).map(|i| i * 8) {
a += mem[i ]; b += mem[i+1];
c += mem[i+2]; d += mem[i+3];
e += mem[i+4]; f += mem[i+5];
g += mem[i+6]; h += mem[i+7];
mix(&mut a, &mut b, &mut c, &mut d,
&mut e, &mut f, &mut g, &mut h);
mem[i ] = a; mem[i+1] = b;
mem[i+2] = c; mem[i+3] = d;
mem[i+4] = e; mem[i+5] = f;
mem[i+6] = g; mem[i+7] = h;
}
}
let mut rng = Isaac64Rng {
rsl: [0; RAND_SIZE],
mem: mem,
a: w(0),
b: w(0),
c: w(0),
index: 0,
half_used: false,
};
// Prepare the first set of results
rng.isaac64();
rng
}
fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64,
e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) {
*a -= *e; *f ^= *h >> 9; *h += *a;
*b -= *f; *g ^= *a << 9; *a += *b;
*c -= *g; *h ^= *b >> 23; *b += *c;
*d -= *h; *a ^= *c << 15; *c += *d;
*e -= *a; *b ^= *d >> 14; *d += *e;
*f -= *b; *c ^= *e << 20; *e += *f;
*g -= *c; *d ^= *f >> 17; *f += *g;
*h -= *d; *e ^= *g << 14; *g += *h;
}
impl Rand for Isaac64Rng {
fn rand<R: Rng>(other: &mut R) -> Isaac64Rng {
let mut key = [w(0); RAND_SIZE];
unsafe {
let ptr = key.as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8);
other.fill_bytes(slice);
}
init(key, 2)
}
}
impl<'a> SeedableRng<&'a [u64]> for Isaac64Rng {
fn reseed(&mut self, seed: &'a [u64]) {
*self = Self::from_seed(seed);
}
/// Create an ISAAC random number generator with a seed. This can
/// be any length, although the maximum number of elements used is
/// 256 and any more will be silently ignored. A generator
/// constructed with a given seed will generate the same sequence
/// of values as all other generators constructed with that seed.
fn from_seed(seed: &'a [u64]) -> Isaac64Rng {
let mut key = [w(0); RAND_SIZE];
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
// - 1], 0, 0, ...], to fill `key`.
let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u64));
for (rsl_elem, seed_elem) in key.iter_mut().zip(seed_iter) {
*rsl_elem = w(seed_elem);
}
init(key, 2)
}
}
#[cfg(test)]
mod test {
use {Rng, SeedableRng};
use super::Isaac64Rng;
#[test]
fn test_rng_64_rand_seeded() {
let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
let mut ra: Isaac64Rng = SeedableRng::from_seed(&s[..]);
let mut rb: Isaac64Rng = SeedableRng::from_seed(&s[..]);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_64_seeded() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
rb.gen_ascii_chars().take(100)));
}
#[test]
fn test_rng_64_reseed() {
let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
let mut r: Isaac64Rng = SeedableRng::from_seed(&s[..]);
let string1: String = r.gen_ascii_chars().take(100).collect();
r.reseed(&s[..]);
let string2: String = r.gen_ascii_chars().take(100).collect();
assert_eq!(string1, string2);
}
#[test]
fn test_rng_64_true_values() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = (0..10).map(|_| ra.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
vec!(547121783600835980, 14377643087320773276, 17351601304698403469,
1238879483818134882, 11952566807690396487, 13970131091560099343,
4469761996653280935, 15552757044682284409, 6860251611068737823,
13722198873481261842));
let seed: &[_] = &[12345, 67890, 54321, 9876];
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
for _ in 0..10000 { rb.next_u64(); }
let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
vec!(18143823860592706164, 8491801882678285927, 2699425367717515619,
17196852593171130876, 2606123525235546165, 15790932315217671084,
596345674630742204, 9947027391921273664, 11788097613744130851,
10391409374914919106));
}
#[test]
fn test_isaac64_true_values_32() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut rng1 = Isaac64Rng::from_seed(seed);
let v = (0..12).map(|_| rng1.next_u32()).collect::<Vec<_>>();
// Subset of above values, as an LE u32 sequence
assert_eq!(v,
[141028748, 127386717,
1058730652, 3347555894,
851491469, 4039984500,
2692730210, 288449107,
646103879, 2782923823,
4195642895, 3252674613]);
}
#[test]
fn test_isaac64_true_values_mixed() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut rng = Isaac64Rng::from_seed(seed);
// Test alternating between `next_u64` and `next_u32` works as expected.
// Values are the same as `test_isaac64_true_values` and
// `test_isaac64_true_values_32`.
assert_eq!(rng.next_u64(), 547121783600835980);
assert_eq!(rng.next_u32(), 1058730652);
assert_eq!(rng.next_u32(), 3347555894);
assert_eq!(rng.next_u64(), 17351601304698403469);
assert_eq!(rng.next_u32(), 2692730210);
// Skip one u32
assert_eq!(rng.next_u64(), 11952566807690396487);
assert_eq!(rng.next_u32(), 4195642895);
}
#[test]
fn test_isaac64_true_bytes() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut rng1 = Isaac64Rng::from_seed(seed);
let mut buf = [0u8; 32];
rng1.fill_bytes(&mut buf);
// Same as first values in test_isaac64_true_values as bytes in LE order
assert_eq!(buf,
[140, 237, 103, 8, 93, 196, 151, 7,
156, 242, 26, 63, 54, 166, 135, 199,
141, 186, 192, 50, 116, 69, 205, 240,
98, 205, 127, 160, 83, 98, 49, 17]);
}
#[test]
fn test_isaac_new_uninitialized() {
// Compare the results from initializing `IsaacRng` with
// `new_from_u64(0)`, to make sure it is the same as the reference
// implementation when used uninitialized.
// Note: We only test the first 16 integers, not the full 256 of the
// first block.
let mut rng = Isaac64Rng::new_from_u64(0);
let vec = (0..16).map(|_| rng.next_u64()).collect::<Vec<_>>();
let expected: [u64; 16] = [
0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB,
0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49,
0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F,
0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF,
0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD,
0xB9090F3D42D2D2EA];
assert_eq!(vec, expected);
}
#[test]
fn test_rng_clone() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);
let mut clone = rng.clone();
for _ in 0..16 {
assert_eq!(rng.next_u64(), clone.next_u64());
}
}
}

51
src/prng/mod.rs Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2017 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.
//! Pseudo random number generators are algorithms to produce *apparently
//! random* numbers deterministically, and usually fairly quickly.
//!
//! So long as the algorithm is computationally secure, is initialised with
//! sufficient entropy (i.e. unknown by an attacker), and its internal state is
//! also protected (unknown to an attacker), the output will also be
//! *computationally secure*. Computationally Secure Pseudo Random Number
//! Generators (CSPRNGs) are thus suitable sources of random numbers for
//! cryptography. There are a couple of gotchas here, however. First, the seed
//! used for initialisation must be unknown. Usually this should be provided by
//! the operating system and should usually be secure, however this may not
//! always be the case (especially soon after startup). Second, user-space
//! memory may be vulnerable, for example when written to swap space, and after
//! forking a child process should reinitialise any user-space PRNGs. For this
//! reason it may be preferable to source random numbers directly from the OS
//! for cryptographic applications.
//!
//! PRNGs are also widely used for non-cryptographic uses: randomised
//! algorithms, simulations, games. In these applications it is usually not
//! important for numbers to be cryptographically *unguessable*, but even
//! distribution and independence from other samples (from the point of view
//! of someone unaware of the algorithm used, at least) may still be important.
//! Good PRNGs should satisfy these properties, but do not take them for
//! granted; Wikipedia's article on
//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
//! provides some background on this topic.
//!
//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have
//! short periods for some seeds. If one PRNG is seeded from another using the
//! same algorithm, it is possible that both will yield the same sequence of
//! values (with some lag).
mod chacha;
mod isaac;
mod isaac64;
mod xorshift;
pub use self::chacha::ChaChaRng;
pub use self::isaac::IsaacRng;
pub use self::isaac64::Isaac64Rng;
pub use self::xorshift::XorShiftRng;

117
src/prng/xorshift.rs Normal file
View File

@ -0,0 +1,117 @@
// Copyright 2017 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.
//! Xorshift generators
use core::num::Wrapping as w;
use core::fmt;
use {Rng, SeedableRng, Rand};
use impls;
/// An Xorshift[1] random number
/// generator.
///
/// The Xorshift algorithm is not suitable for cryptographic purposes
/// but is very fast. If you do not know for sure that it fits your
/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
///
/// [1]: Marsaglia, George (July 2003). ["Xorshift
/// RNGs"](https://www.jstatsoft.org/v08/i14/paper). *Journal of
/// Statistical Software*. Vol. 8 (Issue 14).
#[derive(Clone)]
pub struct XorShiftRng {
x: w<u32>,
y: w<u32>,
z: w<u32>,
w: w<u32>,
}
// Custom Debug implementation that does not expose the internal state
impl fmt::Debug for XorShiftRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "XorShiftRng {{}}")
}
}
impl XorShiftRng {
/// Creates a new XorShiftRng instance which is not seeded.
///
/// The initial values of this RNG are constants, so all generators created
/// by this function will yield the same stream of random numbers. It is
/// highly recommended that this is created through `SeedableRng` instead of
/// this function
pub fn new_unseeded() -> XorShiftRng {
XorShiftRng {
x: w(0x193a6754),
y: w(0xa8a7d469),
z: w(0x97830e05),
w: w(0x113ba7bb),
}
}
}
impl Rng for XorShiftRng {
#[inline]
fn next_u32(&mut self) -> u32 {
let x = self.x;
let t = x ^ (x << 11);
self.x = self.y;
self.y = self.z;
self.z = self.w;
let w_ = self.w;
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
self.w.0
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u32(self, dest)
}
}
impl SeedableRng<[u32; 4]> for XorShiftRng {
/// Reseed an XorShiftRng. This will panic if `seed` is entirely 0.
fn reseed(&mut self, seed: [u32; 4]) {
assert!(!seed.iter().all(|&x| x == 0),
"XorShiftRng.reseed called with an all zero seed.");
self.x = w(seed[0]);
self.y = w(seed[1]);
self.z = w(seed[2]);
self.w = w(seed[3]);
}
/// Create a new XorShiftRng. This will panic if `seed` is entirely 0.
fn from_seed(seed: [u32; 4]) -> XorShiftRng {
assert!(!seed.iter().all(|&x| x == 0),
"XorShiftRng::from_seed called with an all zero seed.");
XorShiftRng {
x: w(seed[0]),
y: w(seed[1]),
z: w(seed[2]),
w: w(seed[3]),
}
}
}
impl Rand for XorShiftRng {
fn rand<R: Rng>(rng: &mut R) -> XorShiftRng {
let mut tuple: (u32, u32, u32, u32) = rng.gen();
while tuple == (0, 0, 0, 0) {
tuple = rng.gen();
}
let (x, y, z, w_) = tuple;
XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }
}
}

View File

@ -10,8 +10,7 @@
//! The implementations of `Rand` for the built-in types. //! The implementations of `Rand` for the built-in types.
use std::char; use core::{char, mem};
use std::mem;
use {Rand,Rng}; use {Rand,Rng};
@ -249,6 +248,7 @@ impl<T:Rand> Rand for Option<T> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use impls;
use {Rng, thread_rng, Open01, Closed01}; use {Rng, thread_rng, Open01, Closed01};
struct ConstantRng(u64); struct ConstantRng(u64);
@ -261,6 +261,10 @@ mod tests {
let ConstantRng(v) = *self; let ConstantRng(v) = *self;
v v
} }
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u64(self, dest)
}
} }
#[test] #[test]

View File

@ -11,7 +11,7 @@
//! A wrapper around another RNG that reseeds it after it //! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes. //! generates a certain number of random bytes.
use std::default::Default; use core::default::Default;
use {Rng, SeedableRng}; use {Rng, SeedableRng};
@ -147,6 +147,7 @@ impl Default for ReseedWithDefault {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use impls;
use std::default::Default; use std::default::Default;
use std::iter::repeat; use std::iter::repeat;
use super::{ReseedingRng, ReseedWithDefault}; use super::{ReseedingRng, ReseedWithDefault};
@ -162,6 +163,13 @@ mod test {
// very random // very random
self.i - 1 self.i - 1
} }
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_u64(self, dest)
}
} }
impl Default for Counter { impl Default for Counter {
fn default() -> Counter { fn default() -> Counter {

337
src/seq.rs Normal file
View File

@ -0,0 +1,337 @@
// Copyright 2017 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.
//! Functions for randomly accessing and sampling sequences.
use super::Rng;
// This crate is only enabled when either std or alloc is available.
// BTreeMap is not as fast in tests, but better than nothing.
#[cfg(feature="std")] use std::collections::HashMap;
#[cfg(not(feature="std"))] use alloc::btree_map::BTreeMap;
#[cfg(not(feature="std"))] use alloc::Vec;
/// Randomly sample `amount` elements from a finite iterator.
///
/// The following can be returned:
/// - `Ok`: `Vec` of `amount` non-repeating randomly sampled elements. The order is not random.
/// - `Err`: `Vec` of all the elements from `iterable` in sequential order. This happens when the
/// length of `iterable` was less than `amount`. This is considered an error since exactly
/// `amount` elements is typically expected.
///
/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let sample = seq::sample_iter(&mut rng, 1..100, 5).unwrap();
/// println!("{:?}", sample);
/// ```
pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Result<Vec<T>, Vec<T>>
where I: IntoIterator<Item=T>,
R: Rng,
{
let mut iter = iterable.into_iter();
let mut reservoir = Vec::with_capacity(amount);
reservoir.extend(iter.by_ref().take(amount));
// Continue unless the iterator was exhausted
//
// note: this prevents iterators that "restart" from causing problems.
// If the iterator stops once, then so do we.
if reservoir.len() == amount {
for (i, elem) in iter.enumerate() {
let k = rng.gen_range(0, i + 1 + amount);
if let Some(spot) = reservoir.get_mut(k) {
*spot = elem;
}
}
Ok(reservoir)
} else {
// Don't hang onto extra memory. There is a corner case where
// `amount` was much less than `len(iterable)`.
reservoir.shrink_to_fit();
Err(reservoir)
}
}
/// Randomly sample exactly `amount` values from `slice`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > slice.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
/// ```
pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
where R: Rng,
T: Clone
{
let indices = sample_indices(rng, slice.len(), amount);
let mut out = Vec::with_capacity(amount);
out.extend(indices.iter().map(|i| slice[*i].clone()));
out
}
/// Randomly sample exactly `amount` references from `slice`.
///
/// The references are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > slice.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
/// ```
pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
where R: Rng
{
let indices = sample_indices(rng, slice.len(), amount);
let mut out = Vec::with_capacity(amount);
out.extend(indices.iter().map(|i| &slice[*i]));
out
}
/// Randomly sample exactly `amount` indices from `0..length`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
/// have the indices themselves so this is provided as an alternative.
///
/// Panics if `amount > length`
pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
where R: Rng,
{
if amount > length {
panic!("`amount` must be less than or equal to `slice.len()`");
}
// We are going to have to allocate at least `amount` for the output no matter what. However,
// if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
// it inserts an element for every loop.
//
// Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
// In fact, benchmarks show the inplace version is faster for length up to about 20 times
// faster than amount.
//
// TODO: there is probably even more fine-tuning that can be done here since
// `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
// and a trade off could probably be made between memory/cpu, since hashmap operations
// are slower than array index swapping.
if amount >= length / 20 {
sample_indices_inplace(rng, length, amount)
} else {
sample_indices_cache(rng, length, amount)
}
}
/// Sample an amount of indices using an inplace partial fisher yates method.
///
/// This allocates the entire `length` of indices and randomizes only the first `amount`.
/// It then truncates to `amount` and returns.
///
/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
/// require allocating an extra cache and is much faster.
fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
where R: Rng,
{
debug_assert!(amount <= length);
let mut indices: Vec<usize> = Vec::with_capacity(length);
indices.extend(0..length);
for i in 0..amount {
let j: usize = rng.gen_range(i, length);
let tmp = indices[i];
indices[i] = indices[j];
indices[j] = tmp;
}
indices.truncate(amount);
debug_assert_eq!(indices.len(), amount);
indices
}
/// This method performs a partial fisher-yates on a range of indices using a HashMap
/// as a cache to record potential collisions.
///
/// The cache avoids allocating the entire `length` of values. This is especially useful when
/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
fn sample_indices_cache<R>(
rng: &mut R,
length: usize,
amount: usize,
) -> Vec<usize>
where R: Rng,
{
debug_assert!(amount <= length);
#[cfg(feature="std")] let mut cache = HashMap::with_capacity(amount);
#[cfg(not(feature="std"))] let mut cache = BTreeMap::new();
let mut out = Vec::with_capacity(amount);
for i in 0..amount {
let j: usize = rng.gen_range(i, length);
// equiv: let tmp = slice[i];
let tmp = match cache.get(&i) {
Some(e) => *e,
None => i,
};
// equiv: slice[i] = slice[j];
let x = match cache.get(&j) {
Some(x) => *x,
None => j,
};
// equiv: slice[j] = tmp;
cache.insert(j, tmp);
// note that in the inplace version, slice[i] is automatically "returned" value
out.push(x);
}
debug_assert_eq!(out.len(), amount);
out
}
#[cfg(test)]
mod test {
use super::*;
use {thread_rng, XorShiftRng, SeedableRng};
#[test]
fn test_sample_iter() {
let min_val = 1;
let max_val = 100;
let mut r = thread_rng();
let vals = (min_val..max_val).collect::<Vec<i32>>();
let small_sample = sample_iter(&mut r, vals.iter(), 5).unwrap();
let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5).unwrap_err();
assert_eq!(small_sample.len(), 5);
assert_eq!(large_sample.len(), vals.len());
// no randomization happens when amount >= len
assert_eq!(large_sample, vals.iter().collect::<Vec<_>>());
assert!(small_sample.iter().all(|e| {
**e >= min_val && **e <= max_val
}));
}
#[test]
fn test_sample_slice_boundaries() {
let empty: &[u8] = &[];
let mut r = thread_rng();
// sample 0 items
assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);
// sample 1 item
assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
let v = sample_slice(&mut r, &[1, 42], 1)[0];
assert!(v == 1 || v == 42);
// sample "all" the items
let v = sample_slice(&mut r, &[42, 133], 2);
assert!(v == vec![42, 133] || v == vec![133, 42]);
assert_eq!(sample_indices_inplace(&mut r, 0, 0), vec![]);
assert_eq!(sample_indices_inplace(&mut r, 1, 0), vec![]);
assert_eq!(sample_indices_inplace(&mut r, 1, 1), vec![0]);
assert_eq!(sample_indices_cache(&mut r, 0, 0), vec![]);
assert_eq!(sample_indices_cache(&mut r, 1, 0), vec![]);
assert_eq!(sample_indices_cache(&mut r, 1, 1), vec![0]);
// Make sure lucky 777's aren't lucky
let slice = &[42, 777];
let mut num_42 = 0;
let total = 1000;
for _ in 0..total {
let v = sample_slice(&mut r, slice, 1);
assert_eq!(v.len(), 1);
let v = v[0];
assert!(v == 42 || v == 777);
if v == 42 {
num_42 += 1;
}
}
let ratio_42 = num_42 as f64 / 1000 as f64;
assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42);
}
#[test]
fn test_sample_slice() {
let xor_rng = XorShiftRng::from_seed;
let max_range = 100;
let mut r = thread_rng();
for length in 1usize..max_range {
let amount = r.gen_range(0, length);
let seed: [u32; 4] = [
r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
];
println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);
// assert that the two index methods give exactly the same result
let inplace = sample_indices_inplace(
&mut xor_rng(seed), length, amount);
let cache = sample_indices_cache(
&mut xor_rng(seed), length, amount);
assert_eq!(inplace, cache);
// assert the basics work
let regular = sample_indices(
&mut xor_rng(seed), length, amount);
assert_eq!(regular.len(), amount);
assert!(regular.iter().all(|e| *e < length));
assert_eq!(regular, inplace);
// also test that sampling the slice works
let vec: Vec<usize> = (0..length).collect();
{
let result = sample_slice(&mut xor_rng(seed), &vec, amount);
assert_eq!(result, regular);
}
{
let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
assert_eq!(result, expected);
}
}
}
}

127
utils/ziggurat_tables.py Executable file
View File

@ -0,0 +1,127 @@
#!/usr/bin/env python
#
# Copyright 2013 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.
# This creates the tables used for distributions implemented using the
# ziggurat algorithm in `rand::distributions;`. They are
# (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
# They are changed rarely, so the generated file should be checked in
# to git.
#
# It creates 3 tables: X as in the paper, F which is f(x_i), and
# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached
# values which is not done in that paper (but is done in other
# variants). Note that the adZigR table is unnecessary because of
# algebra.
#
# It is designed to be compatible with Python 2 and 3.
from math import exp, sqrt, log, floor
import random
# The order should match the return value of `tables`
TABLE_NAMES = ['X', 'F']
# The actual length of the table is 1 more, to stop
# index-out-of-bounds errors. This should match the bitwise operation
# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and
# *_V constants below depend on this value.
TABLE_LEN = 256
# equivalent to `zigNorInit` in Doornik2005, but generalised to any
# distribution. r = dR, v = dV, f = probability density function,
# f_inv = inverse of f
def tables(r, v, f, f_inv):
# compute the x_i
xvec = [0]*(TABLE_LEN+1)
xvec[0] = v / f(r)
xvec[1] = r
for i in range(2, TABLE_LEN):
last = xvec[i-1]
xvec[i] = f_inv(v / last + f(last))
# cache the f's
fvec = [0]*(TABLE_LEN+1)
for i in range(TABLE_LEN+1):
fvec[i] = f(xvec[i])
return xvec, fvec
# Distributions
# N(0, 1)
def norm_f(x):
return exp(-x*x/2.0)
def norm_f_inv(y):
return sqrt(-2.0*log(y))
NORM_R = 3.6541528853610088
NORM_V = 0.00492867323399
NORM = tables(NORM_R, NORM_V,
norm_f, norm_f_inv)
# Exp(1)
def exp_f(x):
return exp(-x)
def exp_f_inv(y):
return -log(y)
EXP_R = 7.69711747013104972
EXP_V = 0.0039496598225815571993
EXP = tables(EXP_R, EXP_V,
exp_f, exp_f_inv)
# Output the tables/constants/types
def render_static(name, type, value):
# no space or
return 'pub static %s: %s =%s;\n' % (name, type, value)
# static `name`: [`type`, .. `len(values)`] =
# [values[0], ..., values[3],
# values[4], ..., values[7],
# ... ];
def render_table(name, values):
rows = []
# 4 values on each row
for i in range(0, len(values), 4):
row = values[i:i+4]
rows.append(', '.join('%.18f' % f for f in row))
rendered = '\n [%s]' % ',\n '.join(rows)
return render_static(name, '[f64, .. %d]' % len(values), rendered)
with open('ziggurat_tables.rs', 'w') as f:
f.write('''// Copyright 2013 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.
// Tables for distributions which are sampled using the ziggurat
// algorithm. Autogenerated by `ziggurat_tables.py`.
pub type ZigTable = &\'static [f64, .. %d];
''' % (TABLE_LEN + 1))
for name, tables, r in [('NORM', NORM, NORM_R),
('EXP', EXP, EXP_R)]:
f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r))
for (tabname, table) in zip(TABLE_NAMES, tables):
f.write(render_table('ZIG_%s_%s' % (name, tabname), table))