1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // https://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 
11 //! The ISAAC-64 random number generator.
12 
13 use core::{fmt, slice};
14 use core::num::Wrapping as w;
15 use rand_core::{RngCore, SeedableRng, Error, le};
16 use rand_core::block::{BlockRngCore, BlockRng64};
17 use prng::isaac_array::IsaacArray;
18 
19 #[allow(non_camel_case_types)]
20 type w64 = w<u64>;
21 
22 const RAND_SIZE_LEN: usize = 8;
23 const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
24 
25 /// A random number generator that uses ISAAC-64, the 64-bit variant of the
26 /// ISAAC algorithm.
27 ///
28 /// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
29 /// the principal bitwise operations employed. It is the most advanced of a
30 /// series of array based random number generator designed by Robert Jenkins
31 /// in 1996[^1].
32 ///
33 /// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
34 /// instead of 32-bit, it uses twice as much memory to hold its state and
35 /// results. Also it uses different constants for shifts and indirect indexing,
36 /// optimized to give good results for 64bit arithmetic.
37 ///
38 /// ISAAC-64 is notably fast and produces excellent quality random numbers for
39 /// non-cryptographic applications.
40 ///
41 /// In spite of being designed with cryptographic security in mind, ISAAC hasn't
42 /// been stringently cryptanalyzed and thus cryptographers do not not
43 /// consensually trust it to be secure. When looking for a secure RNG, prefer
44 /// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of
45 /// the stream-ciphers selected the by eSTREAM contest.
46 ///
47 /// ## Overview of the ISAAC-64 algorithm:
48 /// (in pseudo-code)
49 ///
50 /// ```text
51 /// Input: a, b, c, s[256] // state
52 /// Output: r[256] // results
53 ///
54 /// mix(a,i) = !(a ^ a << 21)  if i = 0 mod 4
55 ///              a ^ a >>  5   if i = 1 mod 4
56 ///              a ^ a << 12   if i = 2 mod 4
57 ///              a ^ a >> 33   if i = 3 mod 4
58 ///
59 /// c = c + 1
60 /// b = b + c
61 ///
62 /// for i in 0..256 {
63 ///     x = s_[i]
64 ///     a = mix(a,i) + s[i+128 mod 256]
65 ///     y = a + b + s[x>>3 mod 256]
66 ///     s[i] = y
67 ///     b = x + s[y>>11 mod 256]
68 ///     r[i] = b
69 /// }
70 /// ```
71 ///
72 /// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods.
73 ///
74 /// See for more information the documentation of [`IsaacRng`].
75 ///
76 /// [^1]: Bob Jenkins, [*ISAAC and RC4*](
77 ///       http://burtleburtle.net/bob/rand/isaac.html)
78 ///
79 /// [`IsaacRng`]: ../isaac/struct.IsaacRng.html
80 /// [`Hc128Rng`]: ../hc128/struct.Hc128Rng.html
81 /// [`BlockRng64`]: ../../../rand_core/block/struct.BlockRng64.html
82 /// [`RngCore`]: ../../trait.RngCore.html
83 #[derive(Clone, Debug)]
84 #[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
85 pub struct Isaac64Rng(BlockRng64<Isaac64Core>);
86 
87 impl RngCore for Isaac64Rng {
88     #[inline(always)]
next_u32(&mut self) -> u3289     fn next_u32(&mut self) -> u32 {
90         self.0.next_u32()
91     }
92 
93     #[inline(always)]
next_u64(&mut self) -> u6494     fn next_u64(&mut self) -> u64 {
95         self.0.next_u64()
96     }
97 
fill_bytes(&mut self, dest: &mut [u8])98     fn fill_bytes(&mut self, dest: &mut [u8]) {
99         self.0.fill_bytes(dest)
100     }
101 
try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>102     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
103         self.0.try_fill_bytes(dest)
104     }
105 }
106 
107 impl SeedableRng for Isaac64Rng {
108     type Seed = <Isaac64Core as SeedableRng>::Seed;
109 
from_seed(seed: Self::Seed) -> Self110     fn from_seed(seed: Self::Seed) -> Self {
111         Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed))
112     }
113 
114     /// Create an ISAAC random number generator using an `u64` as seed.
115     /// If `seed == 0` this will produce the same stream of random numbers as
116     /// the reference implementation when used unseeded.
seed_from_u64(seed: u64) -> Self117     fn seed_from_u64(seed: u64) -> Self {
118         Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed))
119     }
120 
from_rng<S: RngCore>(rng: S) -> Result<Self, Error>121     fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
122         BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng))
123     }
124 }
125 
126 impl Isaac64Rng {
127     /// Create a 64-bit ISAAC random number generator using the
128     /// default fixed seed.
129     ///
130     /// DEPRECATED. `Isaac64Rng::new_from_u64(0)` will produce identical results.
131     #[deprecated(since="0.5.0", note="use the FromEntropy or SeedableRng trait")]
new_unseeded() -> Self132     pub fn new_unseeded() -> Self {
133         Self::seed_from_u64(0)
134     }
135 
136     /// Create an ISAAC-64 random number generator using an `u64` as seed.
137     /// If `seed == 0` this will produce the same stream of random numbers as
138     /// the reference implementation when used unseeded.
139     #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
new_from_u64(seed: u64) -> Self140     pub fn new_from_u64(seed: u64) -> Self {
141         Self::seed_from_u64(seed)
142     }
143 }
144 
145 /// The core of `Isaac64Rng`, used with `BlockRng`.
146 #[derive(Clone)]
147 #[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
148 pub struct Isaac64Core {
149     #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))]
150     mem: [w64; RAND_SIZE],
151     a: w64,
152     b: w64,
153     c: w64,
154 }
155 
156 // Custom Debug implementation that does not expose the internal state
157 impl fmt::Debug for Isaac64Core {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result158     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159         write!(f, "Isaac64Core {{}}")
160     }
161 }
162 
163 impl BlockRngCore for Isaac64Core {
164     type Item = u64;
165     type Results = IsaacArray<Self::Item>;
166 
167     /// Refills the output buffer, `results`. See also the pseudocode desciption
168     /// of the algorithm in the [`Isaac64Rng`] documentation.
169     ///
170     /// Optimisations used (similar to the reference implementation):
171     ///
172     /// - The loop is unrolled 4 times, once for every constant of mix().
173     /// - The contents of the main loop are moved to a function `rngstep`, to
174     ///   reduce code duplication.
175     /// - We use local variables for a and b, which helps with optimisations.
176     /// - We split the main loop in two, one that operates over 0..128 and one
177     ///   over 128..256. This way we can optimise out the addition and modulus
178     ///   from `s[i+128 mod 256]`.
179     /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
180     ///   `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
181     ///   arithmetic.
182     /// - We fill `results` backwards. The reference implementation reads values
183     ///   from `results` in reverse. We read them in the normal direction, to
184     ///   make `fill_bytes` a memcopy. To maintain compatibility we fill in
185     ///   reverse.
186     ///
187     /// [`Isaac64Rng`]: struct.Isaac64Rng.html
generate(&mut self, results: &mut IsaacArray<Self::Item>)188     fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
189         self.c += w(1);
190         // abbreviations
191         let mut a = self.a;
192         let mut b = self.b + self.c;
193         const MIDPOINT: usize = RAND_SIZE / 2;
194 
195         #[inline]
196         fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 {
197             let index = (v >> amount).0 as usize % RAND_SIZE;
198             mem[index]
199         }
200 
201         #[inline]
202         fn rngstep(mem: &mut [w64; RAND_SIZE],
203                    results: &mut [u64; RAND_SIZE],
204                    mix: w64,
205                    a: &mut w64,
206                    b: &mut w64,
207                    base: usize,
208                    m: usize,
209                    m2: usize) {
210             let x = mem[base + m];
211             *a = mix + mem[base + m2];
212             let y = *a + *b + ind(&mem, x, 3);
213             mem[base + m] = y;
214             *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN);
215             results[RAND_SIZE - 1 - base - m] = (*b).0;
216         }
217 
218         let mut m = 0;
219         let mut m2 = MIDPOINT;
220         for i in (0..MIDPOINT/4).map(|i| i * 4) {
221             rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
222             rngstep(&mut self.mem, results,   a ^ (a >> 5 ),  &mut a, &mut b, i + 1, m, m2);
223             rngstep(&mut self.mem, results,   a ^ (a << 12),  &mut a, &mut b, i + 2, m, m2);
224             rngstep(&mut self.mem, results,   a ^ (a >> 33),  &mut a, &mut b, i + 3, m, m2);
225         }
226 
227         m = MIDPOINT;
228         m2 = 0;
229         for i in (0..MIDPOINT/4).map(|i| i * 4) {
230             rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
231             rngstep(&mut self.mem, results,   a ^ (a >> 5 ),  &mut a, &mut b, i + 1, m, m2);
232             rngstep(&mut self.mem, results,   a ^ (a << 12),  &mut a, &mut b, i + 2, m, m2);
233             rngstep(&mut self.mem, results,   a ^ (a >> 33),  &mut a, &mut b, i + 3, m, m2);
234         }
235 
236         self.a = a;
237         self.b = b;
238     }
239 }
240 
241 impl Isaac64Core {
242     /// Create a new ISAAC-64 random number generator.
init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self243     fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self {
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)244         fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64,
245                e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) {
246             *a -= *e; *f ^= *h >> 9;  *h += *a;
247             *b -= *f; *g ^= *a << 9;  *a += *b;
248             *c -= *g; *h ^= *b >> 23; *b += *c;
249             *d -= *h; *a ^= *c << 15; *c += *d;
250             *e -= *a; *b ^= *d >> 14; *d += *e;
251             *f -= *b; *c ^= *e << 20; *e += *f;
252             *g -= *c; *d ^= *f >> 17; *f += *g;
253             *h -= *d; *e ^= *g << 14; *g += *h;
254         }
255 
256         // These numbers are the result of initializing a...h with the
257         // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13)
258         // and applying mix() 4 times.
259         let mut a = w(0x647c4677a2884b7c);
260         let mut b = w(0xb9f8b322c73ac862);
261         let mut c = w(0x8c0ea5053d4712a0);
262         let mut d = w(0xb29b2e824a595524);
263         let mut e = w(0x82f053db8355e0ce);
264         let mut f = w(0x48fe4a0fa5a09315);
265         let mut g = w(0xae985bf2cbfc89ed);
266         let mut h = w(0x98f5704f6c44c0ab);
267 
268         // Normally this should do two passes, to make all of the seed effect
269         // all of `mem`
270         for _ in 0..rounds {
271             for i in (0..RAND_SIZE/8).map(|i| i * 8) {
272                 a += mem[i  ]; b += mem[i+1];
273                 c += mem[i+2]; d += mem[i+3];
274                 e += mem[i+4]; f += mem[i+5];
275                 g += mem[i+6]; h += mem[i+7];
276                 mix(&mut a, &mut b, &mut c, &mut d,
277                     &mut e, &mut f, &mut g, &mut h);
278                 mem[i  ] = a; mem[i+1] = b;
279                 mem[i+2] = c; mem[i+3] = d;
280                 mem[i+4] = e; mem[i+5] = f;
281                 mem[i+6] = g; mem[i+7] = h;
282             }
283         }
284 
285         Self { mem, a: w(0), b: w(0), c: w(0) }
286     }
287 
288     /// Create an ISAAC-64 random number generator using an `u64` as seed.
289     /// If `seed == 0` this will produce the same stream of random numbers as
290     /// the reference implementation when used unseeded.
291     #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
new_from_u64(seed: u64) -> Self292     pub fn new_from_u64(seed: u64) -> Self {
293         Self::seed_from_u64(seed)
294     }
295 }
296 
297 impl SeedableRng for Isaac64Core {
298     type Seed = [u8; 32];
299 
from_seed(seed: Self::Seed) -> Self300     fn from_seed(seed: Self::Seed) -> Self {
301         let mut seed_u64 = [0u64; 4];
302         le::read_u64_into(&seed, &mut seed_u64);
303         // Convert the seed to `Wrapping<u64>` and zero-extend to `RAND_SIZE`.
304         let mut seed_extended = [w(0); RAND_SIZE];
305         for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) {
306             *x = w(*y);
307         }
308         Self::init(seed_extended, 2)
309     }
310 
seed_from_u64(seed: u64) -> Self311     fn seed_from_u64(seed: u64) -> Self {
312         let mut key = [w(0); RAND_SIZE];
313         key[0] = w(seed);
314         // Initialize with only one pass.
315         // A second pass does not improve the quality here, because all of the
316         // seed was already available in the first round.
317         // Not doing the second pass has the small advantage that if
318         // `seed == 0` this method produces exactly the same state as the
319         // reference implementation when used unseeded.
320         Self::init(key, 1)
321     }
322 
from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error>323     fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
324         // Custom `from_rng` implementation that fills a seed with the same size
325         // as the entire state.
326         let mut seed = [w(0u64); RAND_SIZE];
327         unsafe {
328             let ptr = seed.as_mut_ptr() as *mut u8;
329             let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8);
330             rng.try_fill_bytes(slice)?;
331         }
332         for i in seed.iter_mut() {
333             *i = w(i.0.to_le());
334         }
335 
336         Ok(Self::init(seed, 2))
337     }
338 }
339 
340 #[cfg(test)]
341 mod test {
342     use {RngCore, SeedableRng};
343     use super::Isaac64Rng;
344 
345     #[test]
test_isaac64_construction()346     fn test_isaac64_construction() {
347         // Test that various construction techniques produce a working RNG.
348         let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
349                     0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
350         let mut rng1 = Isaac64Rng::from_seed(seed);
351         assert_eq!(rng1.next_u64(), 14964555543728284049);
352 
353         let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap();
354         assert_eq!(rng2.next_u64(), 919595328260451758);
355     }
356 
357     #[test]
test_isaac64_true_values_64()358     fn test_isaac64_true_values_64() {
359         let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
360                     200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
361         let mut rng1 = Isaac64Rng::from_seed(seed);
362         let mut results = [0u64; 10];
363         for i in results.iter_mut() { *i = rng1.next_u64(); }
364         let expected = [
365                    15071495833797886820, 7720185633435529318,
366                    10836773366498097981, 5414053799617603544,
367                    12890513357046278984, 17001051845652595546,
368                    9240803642279356310, 12558996012687158051,
369                    14673053937227185542, 1677046725350116783];
370         assert_eq!(results, expected);
371 
372         let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0,
373                     49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0];
374         let mut rng2 = Isaac64Rng::from_seed(seed);
375         // skip forward to the 10000th number
376         for _ in 0..10000 { rng2.next_u64(); }
377 
378         for i in results.iter_mut() { *i = rng2.next_u64(); }
379         let expected = [
380             18143823860592706164, 8491801882678285927, 2699425367717515619,
381             17196852593171130876, 2606123525235546165, 15790932315217671084,
382             596345674630742204, 9947027391921273664, 11788097613744130851,
383             10391409374914919106];
384         assert_eq!(results, expected);
385     }
386 
387     #[test]
test_isaac64_true_values_32()388     fn test_isaac64_true_values_32() {
389         let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
390                     200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
391         let mut rng = Isaac64Rng::from_seed(seed);
392         let mut results = [0u32; 12];
393         for i in results.iter_mut() { *i = rng.next_u32(); }
394         // Subset of above values, as an LE u32 sequence
395         let expected = [
396                     3477963620, 3509106075,
397                     687845478, 1797495790,
398                     227048253, 2523132918,
399                     4044335064, 1260557630,
400                     4079741768, 3001306521,
401                     69157722, 3958365844];
402         assert_eq!(results, expected);
403     }
404 
405     #[test]
test_isaac64_true_values_mixed()406     fn test_isaac64_true_values_mixed() {
407         let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
408                     200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
409         let mut rng = Isaac64Rng::from_seed(seed);
410         // Test alternating between `next_u64` and `next_u32` works as expected.
411         // Values are the same as `test_isaac64_true_values` and
412         // `test_isaac64_true_values_32`.
413         assert_eq!(rng.next_u64(), 15071495833797886820);
414         assert_eq!(rng.next_u32(), 687845478);
415         assert_eq!(rng.next_u32(), 1797495790);
416         assert_eq!(rng.next_u64(), 10836773366498097981);
417         assert_eq!(rng.next_u32(), 4044335064);
418         // Skip one u32
419         assert_eq!(rng.next_u64(), 12890513357046278984);
420         assert_eq!(rng.next_u32(), 69157722);
421     }
422 
423     #[test]
test_isaac64_true_bytes()424     fn test_isaac64_true_bytes() {
425         let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
426                     200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
427         let mut rng = Isaac64Rng::from_seed(seed);
428         let mut results = [0u8; 32];
429         rng.fill_bytes(&mut results);
430         // Same as first values in test_isaac64_true_values as bytes in LE order
431         let expected = [100, 131, 77, 207, 155, 181, 40, 209,
432                         102, 176, 255, 40, 238, 155, 35, 107,
433                         61, 123, 136, 13, 246, 243, 99, 150,
434                         216, 167, 15, 241, 62, 149, 34, 75];
435         assert_eq!(results, expected);
436     }
437 
438     #[test]
test_isaac64_new_uninitialized()439     fn test_isaac64_new_uninitialized() {
440         // Compare the results from initializing `IsaacRng` with
441         // `seed_from_u64(0)`, to make sure it is the same as the reference
442         // implementation when used uninitialized.
443         // Note: We only test the first 16 integers, not the full 256 of the
444         // first block.
445         let mut rng = Isaac64Rng::seed_from_u64(0);
446         let mut results = [0u64; 16];
447         for i in results.iter_mut() { *i = rng.next_u64(); }
448         let expected: [u64; 16] = [
449             0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB,
450             0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49,
451             0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F,
452             0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF,
453             0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD,
454             0xB9090F3D42D2D2EA];
455         assert_eq!(results, expected);
456     }
457 
458     #[test]
test_isaac64_clone()459     fn test_isaac64_clone() {
460         let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
461                     200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
462         let mut rng1 = Isaac64Rng::from_seed(seed);
463         let mut rng2 = rng1.clone();
464         for _ in 0..16 {
465             assert_eq!(rng1.next_u64(), rng2.next_u64());
466         }
467     }
468 
469     #[test]
470     #[cfg(all(feature="serde1", feature="std"))]
test_isaac64_serde()471     fn test_isaac64_serde() {
472         use bincode;
473         use std::io::{BufWriter, BufReader};
474 
475         let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
476                      57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
477         let mut rng = Isaac64Rng::from_seed(seed);
478 
479         let buf: Vec<u8> = Vec::new();
480         let mut buf = BufWriter::new(buf);
481         bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
482 
483         let buf = buf.into_inner().unwrap();
484         let mut read = BufReader::new(&buf[..]);
485         let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
486 
487         for _ in 0..300 { // more than the 256 buffered results
488             assert_eq!(rng.next_u64(), deserialized.next_u64());
489         }
490     }
491 }
492