aboutsummaryrefslogtreecommitdiff
path: root/rand/rand_isaac/src
diff options
context:
space:
mode:
Diffstat (limited to 'rand/rand_isaac/src')
-rw-r--r--rand/rand_isaac/src/isaac.rs484
-rw-r--r--rand/rand_isaac/src/isaac64.rs481
-rw-r--r--rand/rand_isaac/src/isaac_array.rs136
-rw-r--r--rand/rand_isaac/src/lib.rs36
4 files changed, 1137 insertions, 0 deletions
diff --git a/rand/rand_isaac/src/isaac.rs b/rand/rand_isaac/src/isaac.rs
new file mode 100644
index 0000000..2bfdd94
--- /dev/null
+++ b/rand/rand_isaac/src/isaac.rs
@@ -0,0 +1,484 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC random number generator.
+
+use core::{fmt, slice};
+use core::num::Wrapping as w;
+use rand_core::{RngCore, SeedableRng, Error, le};
+use rand_core::block::{BlockRngCore, BlockRng};
+use isaac_array::IsaacArray;
+
+#[allow(non_camel_case_types)]
+type w32 = w<u32>;
+
+const RAND_SIZE_LEN: usize = 8;
+const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+/// A random number generator that uses the ISAAC algorithm.
+///
+/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
+/// the principal bitwise operations employed. It is the most advanced of a
+/// series of array based random number generator designed by Robert Jenkins
+/// in 1996[^1][^2].
+///
+/// ISAAC is notably fast and produces excellent quality random numbers for
+/// non-cryptographic applications.
+///
+/// In spite of being designed with cryptographic security in mind, ISAAC hasn't
+/// been stringently cryptanalyzed and thus cryptographers do not not
+/// consensually trust it to be secure. When looking for a secure RNG, prefer
+/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of
+/// the stream-ciphers selected the by eSTREAM contest.
+///
+/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
+/// named ISAAC+[^3]. But because the specification is not complete, because
+/// there is no good implementation, and because the suggested bias may not
+/// exist, it is not implemented here.
+///
+/// ## Overview of the ISAAC algorithm:
+/// (in pseudo-code)
+///
+/// ```text
+/// Input: a, b, c, s[256] // state
+/// Output: r[256] // results
+///
+/// mix(a,i) = a ^ a << 13 if i = 0 mod 4
+/// a ^ a >> 6 if i = 1 mod 4
+/// a ^ a << 2 if i = 2 mod 4
+/// a ^ a >> 16 if i = 3 mod 4
+///
+/// c = c + 1
+/// b = b + c
+///
+/// for i in 0..256 {
+/// x = s_[i]
+/// a = f(a,i) + s[i+128 mod 256]
+/// y = a + b + s[x>>2 mod 256]
+/// s[i] = y
+/// b = x + s[y>>10 mod 256]
+/// r[i] = b
+/// }
+/// ```
+///
+/// Numbers are generated in blocks of 256. This means the function above only
+/// runs once every 256 times you ask for a next random number. In all other
+/// circumstances the last element of the results array is returned.
+///
+/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs.
+/// 2 * 256 * 4 = 2 kb to hold the state and results.
+///
+/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods.
+///
+/// ## References
+/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](
+/// http://burtleburtle.net/bob/rand/isaacafa.html)
+///
+/// [^2]: Bob Jenkins, [*ISAAC and RC4*](
+/// http://burtleburtle.net/bob/rand/isaac.html)
+///
+/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*](
+/// https://eprint.iacr.org/2006/438)
+///
+/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html
+/// [`BlockRng`]: ../../rand_core/block/struct.BlockRng.html
+/// [`RngCore`]: ../../rand_core/trait.RngCore.html
+#[derive(Clone, Debug)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct IsaacRng(BlockRng<IsaacCore>);
+
+impl RngCore for IsaacRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for IsaacRng {
+ type Seed = <IsaacCore as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ IsaacRng(BlockRng::<IsaacCore>::from_seed(seed))
+ }
+
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ fn seed_from_u64(seed: u64) -> Self {
+ IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed))
+ }
+
+ fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
+ BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng))
+ }
+}
+
+impl IsaacRng {
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
+ pub fn new_from_u64(seed: u64) -> Self {
+ Self::seed_from_u64(seed)
+ }
+}
+
+/// The core of `IsaacRng`, used with `BlockRng`.
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct IsaacCore {
+ #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))]
+ mem: [w32; RAND_SIZE],
+ a: w32,
+ b: w32,
+ c: w32,
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for IsaacCore {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "IsaacCore {{}}")
+ }
+}
+
+impl BlockRngCore for IsaacCore {
+ type Item = u32;
+ type Results = IsaacArray<Self::Item>;
+
+ /// Refills the output buffer, `results`. See also the pseudocode desciption
+ /// of the algorithm in the [`IsaacRng`] documentation.
+ ///
+ /// Optimisations used (similar to the reference implementation):
+ ///
+ /// - The loop is unrolled 4 times, once for every constant of mix().
+ /// - The contents of the main loop are moved to a function `rngstep`, to
+ /// reduce code duplication.
+ /// - We use local variables for a and b, which helps with optimisations.
+ /// - We split the main loop in two, one that operates over 0..128 and one
+ /// over 128..256. This way we can optimise out the addition and modulus
+ /// from `s[i+128 mod 256]`.
+ /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
+ /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
+ /// arithmetic.
+ /// - We fill `results` backwards. The reference implementation reads values
+ /// from `results` in reverse. We read them in the normal direction, to
+ /// make `fill_bytes` a memcopy. To maintain compatibility we fill in
+ /// reverse.
+ ///
+ /// [`IsaacRng`]: struct.IsaacRng.html
+ fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
+ self.c += w(1);
+ // abbreviations
+ let mut a = self.a;
+ let mut b = self.b + self.c;
+ const MIDPOINT: usize = RAND_SIZE / 2;
+
+ #[inline]
+ fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 {
+ let index = (v >> amount).0 as usize % RAND_SIZE;
+ mem[index]
+ }
+
+ #[inline]
+ fn rngstep(mem: &mut [w32; RAND_SIZE],
+ results: &mut [u32; RAND_SIZE],
+ mix: w32,
+ a: &mut w32,
+ b: &mut w32,
+ base: usize,
+ m: usize,
+ m2: usize) {
+ let x = mem[base + m];
+ *a = mix + mem[base + m2];
+ let y = *a + *b + ind(&mem, x, 2);
+ mem[base + m] = y;
+ *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN);
+ results[RAND_SIZE - 1 - base - m] = (*b).0;
+ }
+
+ let mut m = 0;
+ let mut m2 = MIDPOINT;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ m = MIDPOINT;
+ m2 = 0;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ self.a = a;
+ self.b = b;
+ }
+}
+
+impl IsaacCore {
+ /// Create a new ISAAC random number generator.
+ ///
+ /// The author Bob Jenkins describes how to best initialize ISAAC here:
+ /// <https://rt.cpan.org/Public/Bug/Display.html?id=64324>
+ /// The answer is included here just in case:
+ ///
+ /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will
+ /// do fine, and they should have their expected strength (eg a 40-bit key
+ /// will take as much time to brute force as 40-bit keys usually will). You
+ /// could fill the remainder with 0, but set the last array element to the
+ /// length of the key provided (to distinguish keys that differ only by
+ /// different amounts of 0 padding). You do still need to call `randinit()`
+ /// to make sure the initial state isn't uniform-looking."
+ /// "After publishing ISAAC, I wanted to limit the key to half the size of
+ /// `r[]`, and repeat it twice. That would have made it hard to provide a
+ /// key that sets the whole internal state to anything convenient. But I'd
+ /// already published it."
+ ///
+ /// And his answer to the question "For my code, would repeating the key
+ /// over and over to fill 256 integers be a better solution than
+ /// zero-filling, or would they essentially be the same?":
+ /// "If the seed is under 32 bytes, they're essentially the same, otherwise
+ /// repeating the seed would be stronger. randinit() takes a chunk of 32
+ /// bytes, mixes it, and combines that with the next 32 bytes, et cetera.
+ /// Then loops over all the elements the same way a second time."
+ #[inline]
+ fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self {
+ fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32,
+ e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) {
+ *a ^= *b << 11; *d += *a; *b += *c;
+ *b ^= *c >> 2; *e += *b; *c += *d;
+ *c ^= *d << 8; *f += *c; *d += *e;
+ *d ^= *e >> 16; *g += *d; *e += *f;
+ *e ^= *f << 10; *h += *e; *f += *g;
+ *f ^= *g >> 4; *a += *f; *g += *h;
+ *g ^= *h << 8; *b += *g; *h += *a;
+ *h ^= *a >> 9; *c += *h; *a += *b;
+ }
+
+ // These numbers are the result of initializing a...h with the
+ // fractional part of the golden ratio in binary (0x9e3779b9)
+ // and applying mix() 4 times.
+ let mut a = w(0x1367df5a);
+ let mut b = w(0x95d90059);
+ let mut c = w(0xc3163e4b);
+ let mut d = w(0x0f421ad8);
+ let mut e = w(0xd92a4a78);
+ let mut f = w(0xa51a3c49);
+ let mut g = w(0xc4efea1b);
+ let mut h = w(0x30609119);
+
+ // Normally this should do two passes, to make all of the seed effect
+ // all of `mem`
+ for _ in 0..rounds {
+ for i in (0..RAND_SIZE/8).map(|i| i * 8) {
+ a += mem[i ]; b += mem[i+1];
+ c += mem[i+2]; d += mem[i+3];
+ e += mem[i+4]; f += mem[i+5];
+ g += mem[i+6]; h += mem[i+7];
+ mix(&mut a, &mut b, &mut c, &mut d,
+ &mut e, &mut f, &mut g, &mut h);
+ mem[i ] = a; mem[i+1] = b;
+ mem[i+2] = c; mem[i+3] = d;
+ mem[i+4] = e; mem[i+5] = f;
+ mem[i+6] = g; mem[i+7] = h;
+ }
+ }
+
+ Self { mem, a: w(0), b: w(0), c: w(0) }
+ }
+}
+
+impl SeedableRng for IsaacCore {
+ type Seed = [u8; 32];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u32 = [0u32; 8];
+ le::read_u32_into(&seed, &mut seed_u32);
+ // Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`.
+ let mut seed_extended = [w(0); RAND_SIZE];
+ for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) {
+ *x = w(*y);
+ }
+ Self::init(seed_extended, 2)
+ }
+
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ fn seed_from_u64(seed: u64) -> Self {
+ let mut key = [w(0); RAND_SIZE];
+ key[0] = w(seed as u32);
+ key[1] = w((seed >> 32) as u32);
+ // Initialize with only one pass.
+ // A second pass does not improve the quality here, because all of the
+ // seed was already available in the first round.
+ // Not doing the second pass has the small advantage that if
+ // `seed == 0` this method produces exactly the same state as the
+ // reference implementation when used unseeded.
+ Self::init(key, 1)
+ }
+
+ fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
+ // Custom `from_rng` implementation that fills a seed with the same size
+ // as the entire state.
+ let mut seed = [w(0u32); RAND_SIZE];
+ unsafe {
+ let ptr = seed.as_mut_ptr() as *mut u8;
+
+ let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4);
+ rng.try_fill_bytes(slice)?;
+ }
+ for i in seed.iter_mut() {
+ *i = w(i.0.to_le());
+ }
+
+ Ok(Self::init(seed, 2))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use rand_core::{RngCore, SeedableRng};
+ use super::IsaacRng;
+
+ #[test]
+ fn test_isaac_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = IsaacRng::from_seed(seed);
+ assert_eq!(rng1.next_u32(), 2869442790);
+
+ let mut rng2 = IsaacRng::from_rng(rng1).unwrap();
+ assert_eq!(rng2.next_u32(), 3094074039);
+ }
+
+ #[test]
+ fn test_isaac_true_values_32() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = IsaacRng::from_seed(seed);
+ let mut results = [0u32; 10];
+ for i in results.iter_mut() { *i = rng1.next_u32(); }
+ let expected = [
+ 2558573138, 873787463, 263499565, 2103644246, 3595684709,
+ 4203127393, 264982119, 2765226902, 2737944514, 3900253796];
+ assert_eq!(results, expected);
+
+ let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng2 = IsaacRng::from_seed(seed);
+ // skip forward to the 10000th number
+ for _ in 0..10000 { rng2.next_u32(); }
+
+ for i in results.iter_mut() { *i = rng2.next_u32(); }
+ let expected = [
+ 3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
+ 1576568959, 3507990155, 179069555, 141456972, 2478885421];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_true_values_64() {
+ // As above, using little-endian versions of above values
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = IsaacRng::from_seed(seed);
+ let mut results = [0u64; 5];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected = [
+ 3752888579798383186, 9035083239252078381,18052294697452424037,
+ 11876559110374379111, 16751462502657800130];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_true_bytes() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = IsaacRng::from_seed(seed);
+ let mut results = [0u8; 32];
+ rng.fill_bytes(&mut results);
+ // Same as first values in test_isaac_true_values as bytes in LE order
+ let expected = [82, 186, 128, 152, 71, 240, 20, 52,
+ 45, 175, 180, 15, 86, 16, 99, 125,
+ 101, 203, 81, 214, 97, 162, 134, 250,
+ 103, 78, 203, 15, 150, 3, 210, 164];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_new_uninitialized() {
+ // Compare the results from initializing `IsaacRng` with
+ // `seed_from_u64(0)`, to make sure it is the same as the reference
+ // implementation when used uninitialized.
+ // Note: We only test the first 16 integers, not the full 256 of the
+ // first block.
+ let mut rng = IsaacRng::seed_from_u64(0);
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected: [u32; 16] = [
+ 0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA,
+ 0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD,
+ 0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846,
+ 0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_clone() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = IsaacRng::from_seed(seed);
+ let mut rng2 = rng1.clone();
+ for _ in 0..16 {
+ assert_eq!(rng1.next_u32(), rng2.next_u32());
+ }
+ }
+
+ #[test]
+ #[cfg(feature="serde1")]
+ fn test_isaac_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = IsaacRng::from_seed(seed);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
+
+ for _ in 0..300 { // more than the 256 buffered results
+ assert_eq!(rng.next_u32(), deserialized.next_u32());
+ }
+ }
+}
diff --git a/rand/rand_isaac/src/isaac64.rs b/rand/rand_isaac/src/isaac64.rs
new file mode 100644
index 0000000..2712762
--- /dev/null
+++ b/rand/rand_isaac/src/isaac64.rs
@@ -0,0 +1,481 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC-64 random number generator.
+
+use core::{fmt, slice};
+use core::num::Wrapping as w;
+use rand_core::{RngCore, SeedableRng, Error, le};
+use rand_core::block::{BlockRngCore, BlockRng64};
+use isaac_array::IsaacArray;
+
+#[allow(non_camel_case_types)]
+type w64 = w<u64>;
+
+const RAND_SIZE_LEN: usize = 8;
+const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+/// A random number generator that uses ISAAC-64, the 64-bit variant of the
+/// ISAAC algorithm.
+///
+/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
+/// the principal bitwise operations employed. It is the most advanced of a
+/// series of array based random number generator designed by Robert Jenkins
+/// in 1996[^1].
+///
+/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
+/// instead of 32-bit, it uses twice as much memory to hold its state and
+/// results. Also it uses different constants for shifts and indirect indexing,
+/// optimized to give good results for 64bit arithmetic.
+///
+/// ISAAC-64 is notably fast and produces excellent quality random numbers for
+/// non-cryptographic applications.
+///
+/// In spite of being designed with cryptographic security in mind, ISAAC hasn't
+/// been stringently cryptanalyzed and thus cryptographers do not not
+/// consensually trust it to be secure. When looking for a secure RNG, prefer
+/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of
+/// the stream-ciphers selected the by eSTREAM contest.
+///
+/// ## Overview of the ISAAC-64 algorithm:
+/// (in pseudo-code)
+///
+/// ```text
+/// Input: a, b, c, s[256] // state
+/// Output: r[256] // results
+///
+/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4
+/// a ^ a >> 5 if i = 1 mod 4
+/// a ^ a << 12 if i = 2 mod 4
+/// a ^ a >> 33 if i = 3 mod 4
+///
+/// c = c + 1
+/// b = b + c
+///
+/// for i in 0..256 {
+/// x = s_[i]
+/// a = mix(a,i) + s[i+128 mod 256]
+/// y = a + b + s[x>>3 mod 256]
+/// s[i] = y
+/// b = x + s[y>>11 mod 256]
+/// r[i] = b
+/// }
+/// ```
+///
+/// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods.
+///
+/// See for more information the documentation of [`IsaacRng`].
+///
+/// [^1]: Bob Jenkins, [*ISAAC and RC4*](
+/// http://burtleburtle.net/bob/rand/isaac.html)
+///
+/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html
+/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html
+/// [`BlockRng64`]: ../../rand_core/block/struct.BlockRng64.html
+/// [`RngCore`]: ../../rand_core/trait.RngCore.html
+#[derive(Clone, Debug)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Isaac64Rng(BlockRng64<Isaac64Core>);
+
+impl RngCore for Isaac64Rng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for Isaac64Rng {
+ type Seed = <Isaac64Core as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed))
+ }
+
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ fn seed_from_u64(seed: u64) -> Self {
+ Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed))
+ }
+
+ fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
+ BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng))
+ }
+}
+
+impl Isaac64Rng {
+ /// Create an ISAAC-64 random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
+ pub fn new_from_u64(seed: u64) -> Self {
+ Self::seed_from_u64(seed)
+ }
+}
+
+/// The core of `Isaac64Rng`, used with `BlockRng`.
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Isaac64Core {
+ #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))]
+ mem: [w64; RAND_SIZE],
+ a: w64,
+ b: w64,
+ c: w64,
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for Isaac64Core {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Isaac64Core {{}}")
+ }
+}
+
+impl BlockRngCore for Isaac64Core {
+ type Item = u64;
+ type Results = IsaacArray<Self::Item>;
+
+ /// Refills the output buffer, `results`. See also the pseudocode desciption
+ /// of the algorithm in the [`Isaac64Rng`] documentation.
+ ///
+ /// Optimisations used (similar to the reference implementation):
+ ///
+ /// - The loop is unrolled 4 times, once for every constant of mix().
+ /// - The contents of the main loop are moved to a function `rngstep`, to
+ /// reduce code duplication.
+ /// - We use local variables for a and b, which helps with optimisations.
+ /// - We split the main loop in two, one that operates over 0..128 and one
+ /// over 128..256. This way we can optimise out the addition and modulus
+ /// from `s[i+128 mod 256]`.
+ /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
+ /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
+ /// arithmetic.
+ /// - We fill `results` backwards. The reference implementation reads values
+ /// from `results` in reverse. We read them in the normal direction, to
+ /// make `fill_bytes` a memcopy. To maintain compatibility we fill in
+ /// reverse.
+ ///
+ /// [`Isaac64Rng`]: struct.Isaac64Rng.html
+ fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
+ self.c += w(1);
+ // abbreviations
+ let mut a = self.a;
+ let mut b = self.b + self.c;
+ const MIDPOINT: usize = RAND_SIZE / 2;
+
+ #[inline]
+ fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 {
+ let index = (v >> amount).0 as usize % RAND_SIZE;
+ mem[index]
+ }
+
+ #[inline]
+ fn rngstep(mem: &mut [w64; RAND_SIZE],
+ results: &mut [u64; RAND_SIZE],
+ mix: w64,
+ a: &mut w64,
+ b: &mut w64,
+ base: usize,
+ m: usize,
+ m2: usize) {
+ let x = mem[base + m];
+ *a = mix + mem[base + m2];
+ let y = *a + *b + ind(&mem, x, 3);
+ mem[base + m] = y;
+ *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN);
+ results[RAND_SIZE - 1 - base - m] = (*b).0;
+ }
+
+ let mut m = 0;
+ let mut m2 = MIDPOINT;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ m = MIDPOINT;
+ m2 = 0;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ self.a = a;
+ self.b = b;
+ }
+}
+
+impl Isaac64Core {
+ /// Create a new ISAAC-64 random number generator.
+ fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self {
+ fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64,
+ e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) {
+ *a -= *e; *f ^= *h >> 9; *h += *a;
+ *b -= *f; *g ^= *a << 9; *a += *b;
+ *c -= *g; *h ^= *b >> 23; *b += *c;
+ *d -= *h; *a ^= *c << 15; *c += *d;
+ *e -= *a; *b ^= *d >> 14; *d += *e;
+ *f -= *b; *c ^= *e << 20; *e += *f;
+ *g -= *c; *d ^= *f >> 17; *f += *g;
+ *h -= *d; *e ^= *g << 14; *g += *h;
+ }
+
+ // These numbers are the result of initializing a...h with the
+ // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13)
+ // and applying mix() 4 times.
+ let mut a = w(0x647c4677a2884b7c);
+ let mut b = w(0xb9f8b322c73ac862);
+ let mut c = w(0x8c0ea5053d4712a0);
+ let mut d = w(0xb29b2e824a595524);
+ let mut e = w(0x82f053db8355e0ce);
+ let mut f = w(0x48fe4a0fa5a09315);
+ let mut g = w(0xae985bf2cbfc89ed);
+ let mut h = w(0x98f5704f6c44c0ab);
+
+ // Normally this should do two passes, to make all of the seed effect
+ // all of `mem`
+ for _ in 0..rounds {
+ for i in (0..RAND_SIZE/8).map(|i| i * 8) {
+ a += mem[i ]; b += mem[i+1];
+ c += mem[i+2]; d += mem[i+3];
+ e += mem[i+4]; f += mem[i+5];
+ g += mem[i+6]; h += mem[i+7];
+ mix(&mut a, &mut b, &mut c, &mut d,
+ &mut e, &mut f, &mut g, &mut h);
+ mem[i ] = a; mem[i+1] = b;
+ mem[i+2] = c; mem[i+3] = d;
+ mem[i+4] = e; mem[i+5] = f;
+ mem[i+6] = g; mem[i+7] = h;
+ }
+ }
+
+ Self { mem, a: w(0), b: w(0), c: w(0) }
+ }
+
+ /// Create an ISAAC-64 random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
+ pub fn new_from_u64(seed: u64) -> Self {
+ Self::seed_from_u64(seed)
+ }
+}
+
+impl SeedableRng for Isaac64Core {
+ type Seed = [u8; 32];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u64 = [0u64; 4];
+ le::read_u64_into(&seed, &mut seed_u64);
+ // Convert the seed to `Wrapping<u64>` and zero-extend to `RAND_SIZE`.
+ let mut seed_extended = [w(0); RAND_SIZE];
+ for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) {
+ *x = w(*y);
+ }
+ Self::init(seed_extended, 2)
+ }
+
+ fn seed_from_u64(seed: u64) -> Self {
+ let mut key = [w(0); RAND_SIZE];
+ key[0] = w(seed);
+ // Initialize with only one pass.
+ // A second pass does not improve the quality here, because all of the
+ // seed was already available in the first round.
+ // Not doing the second pass has the small advantage that if
+ // `seed == 0` this method produces exactly the same state as the
+ // reference implementation when used unseeded.
+ Self::init(key, 1)
+ }
+
+ fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
+ // Custom `from_rng` implementation that fills a seed with the same size
+ // as the entire state.
+ let mut seed = [w(0u64); RAND_SIZE];
+ unsafe {
+ let ptr = seed.as_mut_ptr() as *mut u8;
+ let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8);
+ rng.try_fill_bytes(slice)?;
+ }
+ for i in seed.iter_mut() {
+ *i = w(i.0.to_le());
+ }
+
+ Ok(Self::init(seed, 2))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use rand_core::{RngCore, SeedableRng};
+ use super::Isaac64Rng;
+
+ #[test]
+ fn test_isaac64_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = Isaac64Rng::from_seed(seed);
+ assert_eq!(rng1.next_u64(), 14964555543728284049);
+
+ let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap();
+ assert_eq!(rng2.next_u64(), 919595328260451758);
+ }
+
+ #[test]
+ fn test_isaac64_true_values_64() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng1 = Isaac64Rng::from_seed(seed);
+ let mut results = [0u64; 10];
+ for i in results.iter_mut() { *i = rng1.next_u64(); }
+ let expected = [
+ 15071495833797886820, 7720185633435529318,
+ 10836773366498097981, 5414053799617603544,
+ 12890513357046278984, 17001051845652595546,
+ 9240803642279356310, 12558996012687158051,
+ 14673053937227185542, 1677046725350116783];
+ assert_eq!(results, expected);
+
+ let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0,
+ 49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0];
+ let mut rng2 = Isaac64Rng::from_seed(seed);
+ // skip forward to the 10000th number
+ for _ in 0..10000 { rng2.next_u64(); }
+
+ for i in results.iter_mut() { *i = rng2.next_u64(); }
+ let expected = [
+ 18143823860592706164, 8491801882678285927, 2699425367717515619,
+ 17196852593171130876, 2606123525235546165, 15790932315217671084,
+ 596345674630742204, 9947027391921273664, 11788097613744130851,
+ 10391409374914919106];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_true_values_32() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+ let mut results = [0u32; 12];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ // Subset of above values, as an LE u32 sequence
+ let expected = [
+ 3477963620, 3509106075,
+ 687845478, 1797495790,
+ 227048253, 2523132918,
+ 4044335064, 1260557630,
+ 4079741768, 3001306521,
+ 69157722, 3958365844];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_true_values_mixed() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+ // Test alternating between `next_u64` and `next_u32` works as expected.
+ // Values are the same as `test_isaac64_true_values` and
+ // `test_isaac64_true_values_32`.
+ assert_eq!(rng.next_u64(), 15071495833797886820);
+ assert_eq!(rng.next_u32(), 687845478);
+ assert_eq!(rng.next_u32(), 1797495790);
+ assert_eq!(rng.next_u64(), 10836773366498097981);
+ assert_eq!(rng.next_u32(), 4044335064);
+ // Skip one u32
+ assert_eq!(rng.next_u64(), 12890513357046278984);
+ assert_eq!(rng.next_u32(), 69157722);
+ }
+
+ #[test]
+ fn test_isaac64_true_bytes() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+ let mut results = [0u8; 32];
+ rng.fill_bytes(&mut results);
+ // Same as first values in test_isaac64_true_values as bytes in LE order
+ let expected = [100, 131, 77, 207, 155, 181, 40, 209,
+ 102, 176, 255, 40, 238, 155, 35, 107,
+ 61, 123, 136, 13, 246, 243, 99, 150,
+ 216, 167, 15, 241, 62, 149, 34, 75];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_new_uninitialized() {
+ // Compare the results from initializing `IsaacRng` with
+ // `seed_from_u64(0)`, to make sure it is the same as the reference
+ // implementation when used uninitialized.
+ // Note: We only test the first 16 integers, not the full 256 of the
+ // first block.
+ let mut rng = Isaac64Rng::seed_from_u64(0);
+ let mut results = [0u64; 16];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected: [u64; 16] = [
+ 0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB,
+ 0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49,
+ 0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F,
+ 0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF,
+ 0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD,
+ 0xB9090F3D42D2D2EA];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_clone() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng1 = Isaac64Rng::from_seed(seed);
+ let mut rng2 = rng1.clone();
+ for _ in 0..16 {
+ assert_eq!(rng1.next_u64(), rng2.next_u64());
+ }
+ }
+
+ #[test]
+ #[cfg(feature="serde1")]
+ fn test_isaac64_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
+
+ for _ in 0..300 { // more than the 256 buffered results
+ assert_eq!(rng.next_u64(), deserialized.next_u64());
+ }
+ }
+}
diff --git a/rand/rand_isaac/src/isaac_array.rs b/rand/rand_isaac/src/isaac_array.rs
new file mode 100644
index 0000000..0fa6147
--- /dev/null
+++ b/rand/rand_isaac/src/isaac_array.rs
@@ -0,0 +1,136 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2017-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! ISAAC helper functions for 256-element arrays.
+
+// Terrible workaround because arrays with more than 32 elements do not
+// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other
+// traits for that matter.
+
+#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
+
+const RAND_SIZE_LEN: usize = 8;
+const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+
+#[derive(Copy, Clone)]
+#[allow(missing_debug_implementations)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct IsaacArray<T> {
+ #[cfg_attr(feature="serde1",serde(with="isaac_array_serde"))]
+ #[cfg_attr(feature="serde1", serde(bound(
+ serialize = "T: Serialize",
+ deserialize = "T: Deserialize<'de> + Copy + Default")))]
+ inner: [T; RAND_SIZE]
+}
+
+impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> {
+ #[inline(always)]
+ fn as_ref(&self) -> &[T] {
+ &self.inner[..]
+ }
+}
+
+impl<T> ::core::convert::AsMut<[T]> for IsaacArray<T> {
+ #[inline(always)]
+ fn as_mut(&mut self) -> &mut [T] {
+ &mut self.inner[..]
+ }
+}
+
+impl<T> ::core::ops::Deref for IsaacArray<T> {
+ type Target = [T; RAND_SIZE];
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl<T> ::core::ops::DerefMut for IsaacArray<T> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] {
+ &mut self.inner
+ }
+}
+
+impl<T> ::core::default::Default for IsaacArray<T> where T: Copy + Default {
+ fn default() -> IsaacArray<T> {
+ IsaacArray { inner: [T::default(); RAND_SIZE] }
+ }
+}
+
+
+#[cfg(feature="serde1")]
+pub(super) mod isaac_array_serde {
+ const RAND_SIZE_LEN: usize = 8;
+ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+ use serde::{Deserialize, Deserializer, Serialize, Serializer};
+ use serde::de::{Visitor,SeqAccess};
+ use serde::de;
+
+ use core::fmt;
+
+ pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer
+ {
+ use serde::ser::SerializeTuple;
+
+ let mut seq = ser.serialize_tuple(RAND_SIZE)?;
+
+ for e in arr.iter() {
+ seq.serialize_element(&e)?;
+ }
+
+ seq.end()
+ }
+
+ #[inline]
+ pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error>
+ where
+ T: Deserialize<'de>+Default+Copy,
+ D: Deserializer<'de>,
+ {
+ use core::marker::PhantomData;
+ struct ArrayVisitor<T> {
+ _pd: PhantomData<T>,
+ };
+ impl<'de,T> Visitor<'de> for ArrayVisitor<T>
+ where
+ T: Deserialize<'de>+Default+Copy
+ {
+ type Value = [T; RAND_SIZE];
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Isaac state array")
+ }
+
+ #[inline]
+ fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut out = [Default::default();RAND_SIZE];
+
+ for i in 0..RAND_SIZE {
+ match seq.next_element()? {
+ Some(val) => out[i] = val,
+ None => return Err(de::Error::invalid_length(i, &self)),
+ };
+ }
+
+ Ok(out)
+ }
+ }
+
+ de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData})
+ }
+}
diff --git a/rand/rand_isaac/src/lib.rs b/rand/rand_isaac/src/lib.rs
new file mode 100644
index 0000000..ec82d8e
--- /dev/null
+++ b/rand/rand_isaac/src/lib.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC and ISAAC-64 random number generators.
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+#![cfg_attr(not(all(feature="serde1", test)), no_std)]
+
+extern crate rand_core;
+
+#[cfg(feature="serde1")] extern crate serde;
+#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
+
+// To test serialization we need bincode and the standard library
+#[cfg(all(feature="serde1", test))] extern crate bincode;
+#[cfg(all(feature="serde1", test))] extern crate std as core;
+
+pub mod isaac;
+pub mod isaac64;
+
+mod isaac_array;
+
+pub use self::isaac::IsaacRng;
+pub use self::isaac64::Isaac64Rng;