@@ -23,15 +23,70 @@ type w32 = w<u32>;
23
23
const RAND_SIZE_LEN : usize = 8 ;
24
24
const RAND_SIZE : usize = 1 << RAND_SIZE_LEN ;
25
25
26
- /// A random number generator that uses the ISAAC algorithm[1] .
26
+ /// A random number generator that uses the ISAAC algorithm.
27
27
///
28
- /// The ISAAC algorithm is generally accepted as suitable for
29
- /// cryptographic purposes, but this implementation has not be
30
- /// verified as such. Prefer a generator like `OsRng` that defers to
31
- /// the operating system for cases that need high security .
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][2] .
32
32
///
33
- /// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
34
- /// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
33
+ /// Although ISAAC is designed to be cryptographically secure, its design is not
34
+ /// founded in cryptographic theory. Therefore it should _not_ be used for
35
+ /// cryptographic purposes. It is however one of the strongest non-cryptograpic
36
+ /// RNGs, and that while still being reasonably fast.
37
+ ///
38
+ /// Where fast random numbers are needed which should still be secure, but where
39
+ /// speed is more important than absolute (cryptographic) security (e.g. to
40
+ /// initialise hashes in the std library), a generator like ISAAC should be
41
+ /// used.
42
+ ///
43
+ /// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
44
+ /// named ISAAC+[3]. But because the specification is not complete, there is no
45
+ /// good implementation, and because the suggested bias may not exist, it is not
46
+ /// implemented here.
47
+ ///
48
+ /// ## Overview of the ISAAC algorithm:
49
+ /// (in pseudo-code)
50
+ ///
51
+ /// ```text
52
+ /// Input: a, b, c, s[256] // state
53
+ /// Output: r[256] // results
54
+ ///
55
+ /// mix(a,i) = a ^ a << 13 i = 0 mod 4
56
+ /// a ^ a >> 6 i = 1 mod 4
57
+ /// a ^ a << 2 i = 2 mod 4
58
+ /// a ^ a >> 16 i = 3 mod 4
59
+ ///
60
+ /// c = c + 1
61
+ /// b = b + c
62
+ ///
63
+ /// for i in 0..256 {
64
+ /// x = s_[i]
65
+ /// a = f(a,i) + s[i+128 mod 256]
66
+ /// y = a + b + s[x>>2 mod 256]
67
+ /// s[i] = y
68
+ /// b = x + s[y>>10 mod 256]
69
+ /// r[i] = b
70
+ /// }
71
+ /// ```
72
+ ///
73
+ /// Numbers are generated in blocks of 256. This means the function above only
74
+ /// runs once every 256 times you ask for a next random number. In all other
75
+ /// circumstances the last element of the results array is returned.
76
+ ///
77
+ /// ISAAC therefore needs comparatively much memory. 2 * 256 * 4 = 2 kb to hold
78
+ /// the state and results.
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
+ /// (http://eprint.iacr.org/2006/438)
89
+
35
90
#[ derive( Copy ) ]
36
91
pub struct IsaacRng {
37
92
rsl : [ w32 ; RAND_SIZE ] ,
@@ -121,6 +176,20 @@ impl IsaacRng {
121
176
}
122
177
123
178
/// Refills the output buffer (`self.rsl`)
179
+ /// See also the pseudocode desciption of the algorithm at the top of this
180
+ /// file.
181
+ ///
182
+ /// Optimisations used (similar to the reference implementation):
183
+ /// - The loop is unrolled 4 times, once for every constant of mix().
184
+ /// - The contents of the main loop are moved to a function `rngstep`, to
185
+ /// reduce code duplication.
186
+ /// - We use local variables for a and b, which helps with optimisations.
187
+ /// - We split the main loop in two, one that operates over 0..128 and one
188
+ /// over 128..256. This way we can optimise out the addition and modulus
189
+ /// from `s[i+128 mod 256]`.
190
+ /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
191
+ /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
192
+ /// arithmetic.
124
193
fn isaac ( & mut self ) {
125
194
self . c += w ( 1 ) ;
126
195
// abbreviations
0 commit comments