Merge pull request #187 from tatref/patch-1
Fix name of argument in doc
diff --git a/.travis.yml b/.travis.yml
index 1cb2e68..f3d7688 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,5 @@
language: rust
sudo: false
-before_script:
- - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
matrix:
include:
@@ -11,16 +9,21 @@
os: osx
- rust: beta
- rust: nightly
+
+ - rust: nightly
+ before_script:
+ - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
script:
- - cargo test
+ - cargo doc --no-deps --all-features
+ - cargo test --benches
- cargo test --features nightly
- - cargo test --manifest-path rand-derive/Cargo.toml
- - cargo doc --no-deps --features nightly
+ after_success:
+ - travis-cargo --only nightly doc-upload
+
script:
- cargo test
- cargo test --manifest-path rand-derive/Cargo.toml
-after_success:
- - travis-cargo --only nightly doc-upload
+
env:
global:
secure: "BdDntVHSompN+Qxz5Rz45VI4ZqhD72r6aPl166FADlnkIwS6N6FLWdqs51O7G5CpoMXEDvyYrjmRMZe/GYLIG9cmqmn/wUrWPO+PauGiIuG/D2dmfuUNvSTRcIe7UQLXrfP3yyfZPgqsH6pSnNEVopquQKy3KjzqepgriOJtbyY="
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..f8a2ce3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,255 @@
+# 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.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
+
diff --git a/Cargo.toml b/Cargo.toml
index 0700436..b808dea 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rand"
-version = "0.3.17"
+version = "0.4.0-pre.0"
authors = ["The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
@@ -14,11 +14,16 @@
categories = ["algorithms"]
[features]
-i128_support = []
-nightly = ["i128_support"]
+default = ["std"]
+nightly = ["i128_support"] # enables all features requiring nightly rust
+
+std = ["libc"] # default feature; without this rand uses libcore
+alloc = [] # enables Vec and Box support without std
+
+i128_support = [] # enables i128 and u128 support
[dependencies]
-libc = "0.2"
+libc = { version = "0.2", optional = true }
[dev-dependencies]
log = "0.3.0"
@@ -27,4 +32,4 @@
members = ["rand-derive"]
[target.'cfg(target_os = "fuchsia")'.dependencies]
-fuchsia-zircon = "^0.2.1"
+fuchsia-zircon = "0.3"
diff --git a/README.md b/README.md
index cd4ee24..a36c3cd 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,13 @@
extern crate rand;
```
+### Unstable channel
+
+The 'master' branch tracks development code while the '0.3' branch tracks the
+latest stable release. New features are currently being released in an "unstable
+channel"; if you wish to opt-in to the latest releases (expect more breaking
+changes in this channel) specify `rand = "0.4.0-pre.0"`.
+
## 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.
@@ -50,6 +57,48 @@
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)`
You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
diff --git a/appveyor.yml b/appveyor.yml
index 39c6a18..02e217f 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -32,6 +32,7 @@
build: false
test_script:
+ - cargo test --benches
- cargo test
- cargo test --features nightly
- cargo test --manifest-path rand-derive/Cargo.toml
diff --git a/benches/bench.rs b/benches/bench.rs
index 5fa92bd..d396f25 100644
--- a/benches/bench.rs
+++ b/benches/bench.rs
@@ -9,52 +9,7 @@
use std::mem::size_of;
use test::{black_box, Bencher};
-use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, 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;
-}
+use rand::{StdRng, Rng};
#[bench]
fn rand_f32(b: &mut Bencher) {
@@ -77,21 +32,3 @@
});
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);
- })
-}
diff --git a/benches/generators.rs b/benches/generators.rs
new file mode 100644
index 0000000..daee7c5
--- /dev/null
+++ b/benches/generators.rs
@@ -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());
+ });
+}
diff --git a/benches/misc.rs b/benches/misc.rs
new file mode 100644
index 0000000..4251761
--- /dev/null
+++ b/benches/misc.rs
@@ -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);
diff --git a/rand-derive/Cargo.toml b/rand-derive/Cargo.toml
index c3edaff..224b1ed 100644
--- a/rand-derive/Cargo.toml
+++ b/rand-derive/Cargo.toml
@@ -20,4 +20,4 @@
syn = "0.11"
[dev-dependencies]
-rand = { path = "..", version = "0.3" }
+rand = { path = "..", version = "0.4.0-pre.0" }
diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs
index 0a6ad20..5de8efb 100644
--- a/src/distributions/mod.rs
+++ b/src/distributions/mod.rs
@@ -17,20 +17,29 @@
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.
-use std::marker;
+use core::marker;
use {Rng, Rand};
pub use self::range::Range;
+#[cfg(feature="std")]
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
+#[cfg(feature="std")]
pub use self::normal::{Normal, LogNormal};
+#[cfg(feature="std")]
pub use self::exponential::Exp;
pub mod range;
+#[cfg(feature="std")]
pub mod gamma;
+#[cfg(feature="std")]
pub mod normal;
+#[cfg(feature="std")]
pub mod exponential;
+#[cfg(feature="std")]
+mod ziggurat_tables;
+
/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
/// Generate a random value of `Support`, using `rng` as the
@@ -203,8 +212,6 @@
}
}
-mod ziggurat_tables;
-
/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
@@ -220,6 +227,7 @@
// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
+#[cfg(feature="std")]
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(
rng: &mut R,
diff --git a/src/distributions/range.rs b/src/distributions/range.rs
index 7206941..935a00a 100644
--- a/src/distributions/range.rs
+++ b/src/distributions/range.rs
@@ -12,7 +12,7 @@
// this is surprisingly complicated to be both generic & correct
-use std::num::Wrapping as w;
+use core::num::Wrapping as w;
use Rng;
use distributions::{Sample, IndependentSample};
@@ -99,7 +99,7 @@
#[inline]
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
let range = (w(high as $unsigned) - w(low as $unsigned)).0;
- let unsigned_max: $unsigned = ::std::$unsigned::MAX;
+ let unsigned_max: $unsigned = ::core::$unsigned::MAX;
// this is the largest number that fits into $unsigned
// that `range` divides evenly, so, if we've sampled
@@ -136,11 +136,15 @@
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
+#[cfg(feature = "i128_support")]
+integer_impl! { i128, u128 }
integer_impl! { isize, usize }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
+#[cfg(feature = "i128_support")]
+integer_impl! { u128, u128 }
integer_impl! { usize, usize }
macro_rules! float_impl {
@@ -187,7 +191,7 @@
$(
let v: &[($ty, $ty)] = &[(0, 10),
(10, 127),
- (::std::$ty::MIN, ::std::$ty::MAX)];
+ (::core::$ty::MIN, ::core::$ty::MAX)];
for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high);
for _ in 0..1000 {
@@ -200,8 +204,12 @@
)*
}}
}
+ #[cfg(not(feature = "i128_support"))]
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]
diff --git a/src/isaac.rs b/src/isaac.rs
deleted file mode 100644
index b70a8e6..0000000
--- a/src/isaac.rs
+++ /dev/null
@@ -1,635 +0,0 @@
-// 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.
-
-#![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());
- }
- }
-}
diff --git a/src/jitter.rs b/src/jitter.rs
new file mode 100644
index 0000000..4eb5358
--- /dev/null
+++ b/src/jitter.rs
@@ -0,0 +1,759 @@
+// 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;
+
+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 {
+ #[allow(non_camel_case_types)]
+ type LARGE_INTEGER = i64;
+ #[allow(non_camel_case_types)]
+ type BOOL = i32;
+ extern "system" {
+ fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL;
+ }
+
+ let mut t = 0;
+ unsafe { QueryPerformanceCounter(&mut t); }
+ t 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]) {
+ let mut left = dest;
+ while left.len() >= 8 {
+ let (l, r) = {left}.split_at_mut(8);
+ left = r;
+ let chunk: [u8; 8] = unsafe {
+ mem::transmute(self.next_u64().to_le())
+ };
+ l.copy_from_slice(&chunk);
+ }
+ let n = left.len();
+ if n > 0 {
+ let chunk: [u8; 8] = unsafe {
+ mem::transmute(self.next_u64().to_le())
+ };
+ left.copy_from_slice(&chunk[..n]);
+ }
+ }
+}
+
+// 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.
diff --git a/src/lib.rs b/src/lib.rs
index cd856d1..74fdbe3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
// http://rust-lang.org/COPYRIGHT.
//
@@ -184,7 +184,7 @@
//! // 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 {
//! 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
@@ -243,43 +243,54 @@
#![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(feature="std")] extern crate std as core;
+#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
#[cfg(test)] #[macro_use] extern crate log;
+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;
-use std::marker;
-use std::mem;
-use std::io;
-use std::rc::Rc;
-use std::num::Wrapping as w;
-
-pub use os::OsRng;
+pub use jitter::JitterRng;
+#[cfg(feature="std")] pub use os::OsRng;
pub use isaac::{IsaacRng, Isaac64Rng};
pub use chacha::ChaChaRng;
#[cfg(target_pointer_width = "32")]
-use IsaacRng as IsaacWordRng;
+use prng::IsaacRng as IsaacWordRng;
#[cfg(target_pointer_width = "64")]
-use Isaac64Rng as IsaacWordRng;
+use prng::Isaac64Rng as IsaacWordRng;
use distributions::{Range, IndependentSample};
use distributions::range::SampleRange;
+pub use prng::XorShiftRng;
+
pub mod distributions;
-pub mod isaac;
-pub mod chacha;
pub mod reseeding;
mod rand_impls;
-pub mod os;
-pub mod read;
+pub mod jitter;
+#[cfg(feature="std")] pub mod os;
+#[cfg(feature="std")] pub mod read;
+#[cfg(any(feature="std", feature = "alloc"))] pub mod seq;
+mod prng;
-#[allow(bad_style)]
-type w64 = w<u64>;
-#[allow(bad_style)]
-type w32 = w<u32>;
+// 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};
+}
/// A type that can be randomly generated using an `Rng`.
///
@@ -303,8 +314,8 @@
///
/// [`Open01`]: struct.Open01.html
/// [`Closed01`]: struct.Closed01.html
-/// [`Exp1`]: struct.Exp1.html
-/// [`StandardNormal`]: struct.StandardNormal.html
+/// [`Exp1`]: distributions/exponential/struct.Exp1.html
+/// [`StandardNormal`]: distributions/normal/struct.StandardNormal.html
///
/// The following aggregate types also implement `Rand` as long as their
/// component types implement it:
@@ -617,6 +628,7 @@
}
}
+#[cfg(feature="std")]
impl<R: ?Sized> Rng for Box<R> where R: Rng {
fn next_u32(&mut self) -> u32 {
(**self).next_u32()
@@ -714,93 +726,6 @@
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"](http://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
/// open interval `(0,1)` (not including either endpoint).
///
@@ -855,8 +780,19 @@
///
/// Reading the randomness from the OS may fail, and any error is
/// propagated via the `io::Result` return value.
+ #[cfg(feature="std")]
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)
+ }
+ }
+ }
+ }
}
}
@@ -891,31 +827,33 @@
/// seeded `Rng` for consistency over time you should pick one algorithm and
/// create the `Rng` yourself.
///
-/// This will read randomness from the operating system to seed the
-/// generator.
+/// This will seed the generator with randomness from thread_rng.
+#[cfg(feature="std")]
pub fn weak_rng() -> XorShiftRng {
- match OsRng::new() {
- Ok(mut r) => r.gen(),
- Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
- }
+ thread_rng().gen()
}
/// Controls how the thread-local RNG is reseeded.
+#[cfg(feature="std")]
#[derive(Debug)]
struct ThreadRngReseeder;
+#[cfg(feature="std")]
impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
fn reseed(&mut self, rng: &mut StdRng) {
- *rng = match StdRng::new() {
- Ok(r) => r,
- Err(e) => panic!("could not reseed thread_rng: {}", e)
+ match StdRng::new() {
+ Ok(r) => *rng = r,
+ Err(e) => panic!("No entropy available: {}", e),
}
}
}
+#[cfg(feature="std")]
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768;
+#[cfg(feature="std")]
type ThreadRngInner = reseeding::ReseedingRng<StdRng, ThreadRngReseeder>;
/// The thread-local RNG.
+#[cfg(feature="std")]
#[derive(Clone, Debug)]
pub struct ThreadRng {
rng: Rc<RefCell<ThreadRngInner>>,
@@ -925,19 +863,21 @@
/// generator, seeded by the system. Intended to be used in method
/// 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.
+/// After generating a certain amount of randomness, the RNG will reseed itself
+/// 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
/// if the operating system random number generator is rigged to give
/// the same sequence always. If absolute consistency is required,
/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
+#[cfg(feature="std")]
pub fn thread_rng() -> ThreadRng {
// used to make space in TLS for a random number generator
thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = {
let r = match StdRng::new() {
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,
THREAD_RNG_RESEED_THRESHOLD,
@@ -948,6 +888,7 @@
ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}
+#[cfg(feature="std")]
impl Rng for ThreadRng {
fn next_u32(&mut self) -> u32 {
self.rng.borrow_mut().next_u32()
@@ -1005,11 +946,14 @@
/// *x = rng.gen();
/// }
/// ```
+#[cfg(feature="std")]
#[inline]
pub fn random<T: Rand>() -> T {
thread_rng().gen()
}
+/// DEPRECATED: use `seq::sample_iter` instead.
+///
/// Randomly sample up to `amount` elements from a finite iterator.
/// The order of elements in the sample is not random.
///
@@ -1022,27 +966,21 @@
/// let sample = sample(&mut rng, 1..100, 5);
/// 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>
where I: IntoIterator<Item=T>,
R: Rng,
{
- let mut iter = iterable.into_iter();
- let mut reservoir: Vec<T> = iter.by_ref().take(amount).collect();
- // continue unless the iterator was exhausted
- 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
+ // the legacy sample didn't care whether amount was met
+ seq::sample_iter(rng, iterable, amount)
+ .unwrap_or_else(|e| e)
}
#[cfg(test)]
mod test {
- use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample};
+ use super::{Rng, thread_rng, random, SeedableRng, StdRng, weak_rng};
use std::iter::repeat;
pub struct MyRng<R> { inner: R }
@@ -1249,24 +1187,6 @@
}
#[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]
fn test_std_rng_seeded() {
let s = thread_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
let mut ra: StdRng = SeedableRng::from_seed(&s[..]);
@@ -1286,4 +1206,13 @@
let string2 = r.gen_ascii_chars().take(100).collect::<String>();
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)));
+ }
}
diff --git a/src/os.rs b/src/os.rs
index 1eb903a..7ff61a7 100644
--- a/src/os.rs
+++ b/src/os.rs
@@ -53,13 +53,13 @@
}
}
-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];
fill_buf(&mut 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];
fill_buf(&mut buf);
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
@@ -544,6 +544,26 @@
}
}
+#[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)]
mod test {
diff --git a/src/chacha.rs b/src/prng/chacha.rs
similarity index 98%
rename from src/chacha.rs
rename to src/prng/chacha.rs
index 1acec5e..a73e8e7 100644
--- a/src/chacha.rs
+++ b/src/prng/chacha.rs
@@ -10,8 +10,11 @@
//! The ChaCha random number generator.
-use std::num::Wrapping as w;
-use {Rng, SeedableRng, Rand, w32};
+use core::num::Wrapping as w;
+use {Rng, SeedableRng, Rand};
+
+#[allow(bad_style)]
+type w32 = w<u32>;
const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
const STATE_WORDS : usize = 16;
diff --git a/src/prng/isaac.rs b/src/prng/isaac.rs
new file mode 100644
index 0000000..cf5eb67
--- /dev/null
+++ b/src/prng/isaac.rs
@@ -0,0 +1,328 @@
+// 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.
+
+#![allow(non_camel_case_types)]
+
+use core::slice;
+use core::iter::repeat;
+use core::num::Wrapping as w;
+use core::fmt;
+
+use {Rng, SeedableRng, Rand};
+
+#[allow(bad_style)]
+type w32 = w<u32>;
+
+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 {{}}")
+ }
+}
+
+#[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));
+ }
+}
diff --git a/src/prng/isaac64.rs b/src/prng/isaac64.rs
new file mode 100644
index 0000000..b98e3fe
--- /dev/null
+++ b/src/prng/isaac64.rs
@@ -0,0 +1,340 @@
+// 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};
+
+#[allow(bad_style)]
+type w64 = w<u64>;
+
+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 {
+ #[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::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_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());
+ }
+ }
+}
diff --git a/src/prng/mod.rs b/src/prng/mod.rs
new file mode 100644
index 0000000..ed3e018
--- /dev/null
+++ b/src/prng/mod.rs
@@ -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;
diff --git a/src/prng/xorshift.rs b/src/prng/xorshift.rs
new file mode 100644
index 0000000..dd367e9
--- /dev/null
+++ b/src/prng/xorshift.rs
@@ -0,0 +1,101 @@
+// 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 {Rng, SeedableRng, Rand};
+
+/// 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"](http://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: w<u32>,
+ y: w<u32>,
+ z: w<u32>,
+ w: w<u32>,
+}
+
+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_) }
+ }
+}
diff --git a/src/rand_impls.rs b/src/rand_impls.rs
index a9cf5d9..a865bb6 100644
--- a/src/rand_impls.rs
+++ b/src/rand_impls.rs
@@ -10,8 +10,7 @@
//! The implementations of `Rand` for the built-in types.
-use std::char;
-use std::mem;
+use core::{char, mem};
use {Rand,Rng};
diff --git a/src/reseeding.rs b/src/reseeding.rs
index 2fba9f4..1f24e20 100644
--- a/src/reseeding.rs
+++ b/src/reseeding.rs
@@ -11,7 +11,7 @@
//! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes.
-use std::default::Default;
+use core::default::Default;
use {Rng, SeedableRng};
diff --git a/src/seq.rs b/src/seq.rs
new file mode 100644
index 0000000..a7889fe
--- /dev/null
+++ b/src/seq.rs
@@ -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);
+ }
+ }
+ }
+}
diff --git a/utils/ziggurat_tables.py b/utils/ziggurat_tables.py
new file mode 100755
index 0000000..762f956
--- /dev/null
+++ b/utils/ziggurat_tables.py
@@ -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))