Skip to content

Commit fdf3c83

Browse files
author
Paul Dicker
committed
Add some extra documentation
1 parent 4747665 commit fdf3c83

File tree

3 files changed

+177
-18
lines changed

3 files changed

+177
-18
lines changed

src/prng/isaac.rs

+76-7
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,70 @@ type w32 = w<u32>;
2323
const RAND_SIZE_LEN: usize = 8;
2424
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
2525

26-
/// A random number generator that uses the ISAAC algorithm[1].
26+
/// A random number generator that uses the ISAAC algorithm.
2727
///
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].
3232
///
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+
3590
#[derive(Copy)]
3691
pub struct IsaacRng {
3792
rsl: [w32; RAND_SIZE],
@@ -121,6 +176,20 @@ impl IsaacRng {
121176
}
122177

123178
/// 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.
124193
fn isaac(&mut self) {
125194
self.c += w(1);
126195
// abbreviations

src/prng/isaac64.rs

+61-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! The ISAAC random number generator.
11+
//! The ISAAC-64 random number generator.
1212
1313
use core::slice;
1414
use core::iter::repeat;
@@ -23,16 +23,54 @@ type w64 = w<u64>;
2323
const RAND_SIZE_LEN: usize = 8;
2424
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
2525

26-
/// A random number generator that uses ISAAC-64[1], the 64-bit
27-
/// variant of the ISAAC algorithm.
26+
/// A random number generator that uses ISAAC-64, the 64-bit variant of the
27+
/// ISAAC algorithm.
2828
///
29-
/// The ISAAC algorithm is generally accepted as suitable for
30-
/// cryptographic purposes, but this implementation has not be
31-
/// verified as such. Prefer a generator like `OsRng` that defers to
32-
/// the operating system for cases that need high security.
29+
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
30+
/// the principal bitwise operations employed. It is the most advanced of a
31+
/// series of array based random number generator designed by Robert Jenkins
32+
/// in 1996[1].
3333
///
34-
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
35-
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
34+
/// Although ISAAC is designed to be cryptographically secure, its design is not
35+
/// founded in cryptographic theory. Therefore it should _not_ be used for
36+
/// cryptographic purposes. It is however one of the strongest non-cryptograpic
37+
/// RNGs, and that while still being reasonably fast.
38+
///
39+
/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
40+
/// instead of 32-bit, it uses twice as much memory to hold its state and
41+
/// results. Also it uses different constants for shifts and indirect indexing,
42+
/// optimized to give good results for 64bit arithmetic.
43+
///
44+
/// ## Overview of the ISAAC-64 algorithm:
45+
/// (in pseudo-code)
46+
///
47+
/// ```text
48+
/// Input: a, b, c, s[256] // state
49+
/// Output: r[256] // results
50+
///
51+
/// mix(a,i) = !(a ^ a << 21) i = 0 mod 4
52+
/// a ^ a >> 5 i = 1 mod 4
53+
/// a ^ a << 12 i = 2 mod 4
54+
/// a ^ a >> 33 i = 3 mod 4
55+
///
56+
/// c = c + 1
57+
/// b = b + c
58+
///
59+
/// for i in 0..256 {
60+
/// x = s_[i]
61+
/// a = mix(a,i) + s[i+128 mod 256]
62+
/// y = a + b + s[x>>3 mod 256]
63+
/// s[i] = y
64+
/// b = x + s[y>>11 mod 256]
65+
/// r[i] = b
66+
/// }
67+
/// ```
68+
///
69+
/// See for more information the description in rand::prng::IsaacRng.
70+
///
71+
/// [1]: Bob Jenkins, [*ISAAC and RC4*]
72+
/// (http://burtleburtle.net/bob/rand/isaac.html)
73+
3674
#[derive(Copy)]
3775
pub struct Isaac64Rng {
3876
rsl: [w64; RAND_SIZE],
@@ -122,6 +160,20 @@ impl Isaac64Rng {
122160
}
123161

124162
/// Refills the output buffer (`self.rsl`)
163+
/// See also the pseudocode desciption of the algorithm at the top of this
164+
/// file.
165+
///
166+
/// Optimisations used (similar to the reference implementation):
167+
/// - The loop is unrolled 4 times, once for every constant of mix().
168+
/// - The contents of the main loop are moved to a function `rngstep`, to
169+
/// reduce code duplication.
170+
/// - We use local variables for a and b, which helps with optimisations.
171+
/// - We split the main loop in two, one that operates over 0..128 and one
172+
/// over 128..256. This way we can optimise out the addition and modulus
173+
/// from `s[i+128 mod 256]`.
174+
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
175+
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
176+
/// arithmetic.
125177
fn isaac64(&mut self) {
126178
self.c += w(1);
127179
// abbreviations

src/prng/isaac_word.rs

+40-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,45 @@
1111
//! The ISAAC random number generator.
1212
1313
/// Select 32- or 64-bit variant dependent on pointer size.
14+
15+
use core::fmt;
16+
1417
#[cfg(target_pointer_width = "32")]
15-
pub use prng::isaac::IsaacRng as IsaacWordRng;
18+
#[derive(Copy)]
19+
/// A random number generator that uses the ISAAC or ISAAC-64 algorithm,
20+
/// depending on the pointer size of the target architecture.
21+
///
22+
/// In general a random number generator that internally uses the word size of
23+
/// the target architecture is faster than one that doesn't. Choosing
24+
/// `IsaacWordRng` is therefore often a better choice than `IsaacRng` or
25+
/// `Isaac64Rng`. The orthers can be a good choise if reproducability across
26+
/// different architectures is desired.
27+
///
28+
/// See for an explemation of the algorithm `IsaacRng` and `Isaac64Rng`.
29+
pub struct IsaacWordRng(super::isaac::IsaacRng);
30+
1631
#[cfg(target_pointer_width = "64")]
17-
pub use prng::isaac64::Isaac64Rng as IsaacWordRng;
32+
#[derive(Copy)]
33+
/// A random number generator that uses either the ISAAC or ISAAC-64 algorithm,
34+
/// depending on the pointer size of the target architecture.
35+
///
36+
/// In general a random number generator that internally uses the word size of
37+
/// the target architecture is faster than one that doesn't. Choosing
38+
/// `IsaacWordRng` is therefore often a better choice than `IsaacRng` or
39+
/// `Isaac64Rng`. The orthers can be a good choise if reproducability across
40+
/// different architectures is desired.
41+
///
42+
/// See for an explemation of the algorithm `IsaacRng` and `Isaac64Rng`.
43+
pub struct IsaacWordRng(super::isaac64::Isaac64Rng);
44+
45+
impl Clone for IsaacWordRng {
46+
fn clone(&self) -> IsaacWordRng {
47+
*self
48+
}
49+
}
50+
51+
impl fmt::Debug for IsaacWordRng {
52+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53+
write!(f, "IsaacWordRng {{}}")
54+
}
55+
}

0 commit comments

Comments
 (0)