rand_isaac/isaac.rs
1// Copyright 2018 Developers of the Rand project.
2// Copyright 2013-2018 The Rust Project Developers.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! The ISAAC random number generator.
11
12use core::{fmt, slice};
13use core::num::Wrapping as w;
14#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
15use rand_core::{RngCore, SeedableRng, Error, le};
16use rand_core::block::{BlockRngCore, BlockRng};
17use crate::isaac_array::IsaacArray;
18
19#[allow(non_camel_case_types)]
20type w32 = w<u32>;
21
22const RAND_SIZE_LEN: usize = 8;
23const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
24
25/// A random number generator that uses the ISAAC algorithm.
26///
27/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
28/// the principal bitwise operations employed. It is the most advanced of a
29/// series of array based random number generator designed by Robert Jenkins
30/// in 1996[^1][^2].
31///
32/// ISAAC is notably fast and produces excellent quality random numbers for
33/// non-cryptographic applications.
34///
35/// In spite of being designed with cryptographic security in mind, ISAAC hasn't
36/// been stringently cryptanalyzed and thus cryptographers do not not
37/// consensually trust it to be secure. When looking for a secure RNG, prefer
38/// `Hc128Rng` from the [`rand_hc`] crate instead, which, like ISAAC, is an
39/// array-based RNG and one of the stream-ciphers selected the by eSTREAM
40///
41/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
42/// named ISAAC+[^3]. But because the specification is not complete, because
43/// there is no good implementation, and because the suggested bias may not
44/// exist, it is not implemented here.
45///
46/// ## Overview of the ISAAC algorithm:
47/// (in pseudo-code)
48///
49/// ```text
50/// Input: a, b, c, s[256] // state
51/// Output: r[256] // results
52///
53/// mix(a,i) = a ^ a << 13 if i = 0 mod 4
54/// a ^ a >> 6 if i = 1 mod 4
55/// a ^ a << 2 if i = 2 mod 4
56/// a ^ a >> 16 if i = 3 mod 4
57///
58/// c = c + 1
59/// b = b + c
60///
61/// for i in 0..256 {
62/// x = s_[i]
63/// a = f(a,i) + s[i+128 mod 256]
64/// y = a + b + s[x>>2 mod 256]
65/// s[i] = y
66/// b = x + s[y>>10 mod 256]
67/// r[i] = b
68/// }
69/// ```
70///
71/// Numbers are generated in blocks of 256. This means the function above only
72/// runs once every 256 times you ask for a next random number. In all other
73/// circumstances the last element of the results array is returned.
74///
75/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs.
76/// 2 * 256 * 4 = 2 kb to hold the state and results.
77///
78/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods.
79///
80/// ## References
81/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](
82/// http://burtleburtle.net/bob/rand/isaacafa.html)
83///
84/// [^2]: Bob Jenkins, [*ISAAC and RC4*](
85/// http://burtleburtle.net/bob/rand/isaac.html)
86///
87/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*](
88/// https://eprint.iacr.org/2006/438)
89///
90/// [`rand_hc`]: https://docs.rs/rand_hc
91#[derive(Debug, Clone)]
92#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
93pub struct IsaacRng(BlockRng<IsaacCore>);
94
95impl RngCore for IsaacRng {
96 #[inline]
97 fn next_u32(&mut self) -> u32 {
98 self.0.next_u32()
99 }
100
101 #[inline]
102 fn next_u64(&mut self) -> u64 {
103 self.0.next_u64()
104 }
105
106 #[inline]
107 fn fill_bytes(&mut self, dest: &mut [u8]) {
108 self.0.fill_bytes(dest)
109 }
110
111 #[inline]
112 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
113 self.0.try_fill_bytes(dest)
114 }
115}
116
117impl SeedableRng for IsaacRng {
118 type Seed = <IsaacCore as SeedableRng>::Seed;
119
120 #[inline]
121 fn from_seed(seed: Self::Seed) -> Self {
122 IsaacRng(BlockRng::<IsaacCore>::from_seed(seed))
123 }
124
125 /// Create an ISAAC random number generator using an `u64` as seed.
126 /// If `seed == 0` this will produce the same stream of random numbers as
127 /// the reference implementation when used unseeded.
128 #[inline]
129 fn seed_from_u64(seed: u64) -> Self {
130 IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed))
131 }
132
133 #[inline]
134 fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
135 BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng))
136 }
137}
138
139/// The core of [`IsaacRng`], used with [`BlockRng`].
140#[derive(Clone)]
141#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
142pub struct IsaacCore {
143 #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))]
144 mem: [w32; RAND_SIZE],
145 a: w32,
146 b: w32,
147 c: w32,
148}
149
150// Custom Debug implementation that does not expose the internal state
151impl fmt::Debug for IsaacCore {
152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 write!(f, "IsaacCore {{}}")
154 }
155}
156
157// Custom PartialEq implementation as it can't currently be derived from an array of size RAND_SIZE
158impl ::core::cmp::PartialEq for IsaacCore {
159 fn eq(&self, other: &IsaacCore) -> bool {
160 &self.mem[..] == &other.mem[..]
161 && self.a == other.a
162 && self.b == other.b
163 && self.c == other.c
164 }
165}
166
167// Custom Eq implementation as it can't currently be derived from an array of size RAND_SIZE
168impl ::core::cmp::Eq for IsaacCore {
169}
170
171impl BlockRngCore for IsaacCore {
172 type Item = u32;
173 type Results = IsaacArray<Self::Item>;
174
175 /// Refills the output buffer, `results`. See also the pseudocode desciption
176 /// of the algorithm in the `IsaacRng` documentation.
177 ///
178 /// Optimisations used (similar to the reference implementation):
179 ///
180 /// - The loop is unrolled 4 times, once for every constant of mix().
181 /// - The contents of the main loop are moved to a function `rngstep`, to
182 /// reduce code duplication.
183 /// - We use local variables for a and b, which helps with optimisations.
184 /// - We split the main loop in two, one that operates over 0..128 and one
185 /// over 128..256. This way we can optimise out the addition and modulus
186 /// from `s[i+128 mod 256]`.
187 /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
188 /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
189 /// arithmetic.
190 /// - We fill `results` backwards. The reference implementation reads values
191 /// from `results` in reverse. We read them in the normal direction, to
192 /// make `fill_bytes` a memcopy. To maintain compatibility we fill in
193 /// reverse.
194 fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
195 self.c += w(1);
196 // abbreviations
197 let mut a = self.a;
198 let mut b = self.b + self.c;
199 const MIDPOINT: usize = RAND_SIZE / 2;
200
201 #[inline]
202 fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 {
203 let index = (v >> amount).0 as usize % RAND_SIZE;
204 mem[index]
205 }
206
207 #[inline]
208 fn rngstep(mem: &mut [w32; RAND_SIZE],
209 results: &mut [u32; RAND_SIZE],
210 mix: w32,
211 a: &mut w32,
212 b: &mut w32,
213 base: usize,
214 m: usize,
215 m2: usize) {
216 let x = mem[base + m];
217 *a = mix + mem[base + m2];
218 let y = *a + *b + ind(&mem, x, 2);
219 mem[base + m] = y;
220 *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN);
221 results[RAND_SIZE - 1 - base - m] = (*b).0;
222 }
223
224 let mut m = 0;
225 let mut m2 = MIDPOINT;
226 for i in (0..MIDPOINT/4).map(|i| i * 4) {
227 rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
228 rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
229 rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
230 rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
231 }
232
233 m = MIDPOINT;
234 m2 = 0;
235 for i in (0..MIDPOINT/4).map(|i| i * 4) {
236 rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
237 rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
238 rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
239 rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
240 }
241
242 self.a = a;
243 self.b = b;
244 }
245}
246
247impl IsaacCore {
248 /// Create a new ISAAC random number generator.
249 ///
250 /// The author Bob Jenkins describes how to best initialize ISAAC here:
251 /// <https://rt.cpan.org/Public/Bug/Display.html?id=64324>
252 /// The answer is included here just in case:
253 ///
254 /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will
255 /// do fine, and they should have their expected strength (eg a 40-bit key
256 /// will take as much time to brute force as 40-bit keys usually will). You
257 /// could fill the remainder with 0, but set the last array element to the
258 /// length of the key provided (to distinguish keys that differ only by
259 /// different amounts of 0 padding). You do still need to call `randinit()`
260 /// to make sure the initial state isn't uniform-looking."
261 /// "After publishing ISAAC, I wanted to limit the key to half the size of
262 /// `r[]`, and repeat it twice. That would have made it hard to provide a
263 /// key that sets the whole internal state to anything convenient. But I'd
264 /// already published it."
265 ///
266 /// And his answer to the question "For my code, would repeating the key
267 /// over and over to fill 256 integers be a better solution than
268 /// zero-filling, or would they essentially be the same?":
269 /// "If the seed is under 32 bytes, they're essentially the same, otherwise
270 /// repeating the seed would be stronger. randinit() takes a chunk of 32
271 /// bytes, mixes it, and combines that with the next 32 bytes, et cetera.
272 /// Then loops over all the elements the same way a second time."
273 #[inline]
274 fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self {
275 fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32,
276 e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) {
277 *a ^= *b << 11; *d += *a; *b += *c;
278 *b ^= *c >> 2; *e += *b; *c += *d;
279 *c ^= *d << 8; *f += *c; *d += *e;
280 *d ^= *e >> 16; *g += *d; *e += *f;
281 *e ^= *f << 10; *h += *e; *f += *g;
282 *f ^= *g >> 4; *a += *f; *g += *h;
283 *g ^= *h << 8; *b += *g; *h += *a;
284 *h ^= *a >> 9; *c += *h; *a += *b;
285 }
286
287 // These numbers are the result of initializing a...h with the
288 // fractional part of the golden ratio in binary (0x9e3779b9)
289 // and applying mix() 4 times.
290 let mut a = w(0x1367df5a);
291 let mut b = w(0x95d90059);
292 let mut c = w(0xc3163e4b);
293 let mut d = w(0x0f421ad8);
294 let mut e = w(0xd92a4a78);
295 let mut f = w(0xa51a3c49);
296 let mut g = w(0xc4efea1b);
297 let mut h = w(0x30609119);
298
299 // Normally this should do two passes, to make all of the seed effect
300 // all of `mem`
301 for _ in 0..rounds {
302 for i in (0..RAND_SIZE/8).map(|i| i * 8) {
303 a += mem[i ]; b += mem[i+1];
304 c += mem[i+2]; d += mem[i+3];
305 e += mem[i+4]; f += mem[i+5];
306 g += mem[i+6]; h += mem[i+7];
307 mix(&mut a, &mut b, &mut c, &mut d,
308 &mut e, &mut f, &mut g, &mut h);
309 mem[i ] = a; mem[i+1] = b;
310 mem[i+2] = c; mem[i+3] = d;
311 mem[i+4] = e; mem[i+5] = f;
312 mem[i+6] = g; mem[i+7] = h;
313 }
314 }
315
316 Self { mem, a: w(0), b: w(0), c: w(0) }
317 }
318}
319
320impl SeedableRng for IsaacCore {
321 type Seed = [u8; 32];
322
323 fn from_seed(seed: Self::Seed) -> Self {
324 let mut seed_u32 = [0u32; 8];
325 le::read_u32_into(&seed, &mut seed_u32);
326 // Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`.
327 let mut seed_extended = [w(0); RAND_SIZE];
328 for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) {
329 *x = w(*y);
330 }
331 Self::init(seed_extended, 2)
332 }
333
334 /// Create an ISAAC random number generator using an `u64` as seed.
335 /// If `seed == 0` this will produce the same stream of random numbers as
336 /// the reference implementation when used unseeded.
337 fn seed_from_u64(seed: u64) -> Self {
338 let mut key = [w(0); RAND_SIZE];
339 key[0] = w(seed as u32);
340 key[1] = w((seed >> 32) as u32);
341 // Initialize with only one pass.
342 // A second pass does not improve the quality here, because all of the
343 // seed was already available in the first round.
344 // Not doing the second pass has the small advantage that if
345 // `seed == 0` this method produces exactly the same state as the
346 // reference implementation when used unseeded.
347 Self::init(key, 1)
348 }
349
350 fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
351 // Custom `from_rng` implementation that fills a seed with the same size
352 // as the entire state.
353 let mut seed = [w(0u32); RAND_SIZE];
354 unsafe {
355 let ptr = seed.as_mut_ptr() as *mut u8;
356
357 let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4);
358 rng.try_fill_bytes(slice)?;
359 }
360 for i in seed.iter_mut() {
361 *i = w(i.0.to_le());
362 }
363
364 Ok(Self::init(seed, 2))
365 }
366}
367
368#[cfg(test)]
369mod test {
370 use rand_core::{RngCore, SeedableRng};
371 use super::IsaacRng;
372
373 #[test]
374 fn test_isaac_construction() {
375 // Test that various construction techniques produce a working RNG.
376 let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
377 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
378 let mut rng1 = IsaacRng::from_seed(seed);
379 assert_eq!(rng1.next_u32(), 2869442790);
380
381 let mut rng2 = IsaacRng::from_rng(rng1).unwrap();
382 assert_eq!(rng2.next_u32(), 3094074039);
383 }
384
385 #[test]
386 fn test_isaac_true_values_32() {
387 let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
388 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
389 let mut rng1 = IsaacRng::from_seed(seed);
390 let mut results = [0u32; 10];
391 for i in results.iter_mut() { *i = rng1.next_u32(); }
392 let expected = [
393 2558573138, 873787463, 263499565, 2103644246, 3595684709,
394 4203127393, 264982119, 2765226902, 2737944514, 3900253796];
395 assert_eq!(results, expected);
396
397 let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0,
398 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
399 let mut rng2 = IsaacRng::from_seed(seed);
400 // skip forward to the 10000th number
401 for _ in 0..10000 { rng2.next_u32(); }
402
403 for i in results.iter_mut() { *i = rng2.next_u32(); }
404 let expected = [
405 3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
406 1576568959, 3507990155, 179069555, 141456972, 2478885421];
407 assert_eq!(results, expected);
408 }
409
410 #[test]
411 fn test_isaac_true_values_64() {
412 // As above, using little-endian versions of above values
413 let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
414 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
415 let mut rng = IsaacRng::from_seed(seed);
416 let mut results = [0u64; 5];
417 for i in results.iter_mut() { *i = rng.next_u64(); }
418 let expected = [
419 3752888579798383186, 9035083239252078381,18052294697452424037,
420 11876559110374379111, 16751462502657800130];
421 assert_eq!(results, expected);
422 }
423
424 #[test]
425 fn test_isaac_true_bytes() {
426 let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
427 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
428 let mut rng = IsaacRng::from_seed(seed);
429 let mut results = [0u8; 32];
430 rng.fill_bytes(&mut results);
431 // Same as first values in test_isaac_true_values as bytes in LE order
432 let expected = [82, 186, 128, 152, 71, 240, 20, 52,
433 45, 175, 180, 15, 86, 16, 99, 125,
434 101, 203, 81, 214, 97, 162, 134, 250,
435 103, 78, 203, 15, 150, 3, 210, 164];
436 assert_eq!(results, expected);
437 }
438
439 #[test]
440 fn test_isaac_new_uninitialized() {
441 // Compare the results from initializing `IsaacRng` with
442 // `seed_from_u64(0)`, to make sure it is the same as the reference
443 // implementation when used uninitialized.
444 // Note: We only test the first 16 integers, not the full 256 of the
445 // first block.
446 let mut rng = IsaacRng::seed_from_u64(0);
447 let mut results = [0u32; 16];
448 for i in results.iter_mut() { *i = rng.next_u32(); }
449 let expected: [u32; 16] = [
450 0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA,
451 0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD,
452 0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846,
453 0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F];
454 assert_eq!(results, expected);
455 }
456
457 #[test]
458 fn test_isaac_clone() {
459 let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
460 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
461 let mut rng1 = IsaacRng::from_seed(seed);
462 let mut rng2 = rng1.clone();
463 for _ in 0..16 {
464 assert_eq!(rng1.next_u32(), rng2.next_u32());
465 }
466 }
467
468 #[test]
469 #[cfg(feature="serde1")]
470 fn test_isaac_serde() {
471 use bincode;
472 use std::io::{BufWriter, BufReader};
473
474 let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
475 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
476 let mut rng = IsaacRng::from_seed(seed);
477
478 let buf: Vec<u8> = Vec::new();
479 let mut buf = BufWriter::new(buf);
480 bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
481
482 let buf = buf.into_inner().unwrap();
483 let mut read = BufReader::new(&buf[..]);
484 let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
485
486 for _ in 0..300 { // more than the 256 buffered results
487 assert_eq!(rng.next_u32(), deserialized.next_u32());
488 }
489 }
490}