use core::{fmt, slice};
use core::num::Wrapping as w;
use rand_core::{RngCore, SeedableRng, Error, le};
use rand_core::block::{BlockRngCore, BlockRng};
use prng::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;
#[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))
}
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 {
#[deprecated(since="0.5.0", note="use the FromEntropy or SeedableRng trait")]
pub fn new_unseeded() -> Self {
Self::seed_from_u64(0)
}
#[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)
}
}
#[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,
}
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>;
fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
self.c += w(1);
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 {
#[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;
}
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);
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);
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)
}
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);
Self::init(key, 1)
}
fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
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 {RngCore, SeedableRng};
use super::IsaacRng;
#[test]
fn test_isaac_construction() {
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);
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() {
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);
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() {
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(all(feature="serde1", feature="std"))]
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 { assert_eq!(rng.next_u32(), deserialized.next_u32());
}
}
}