Skip to content

Commit

Permalink
Add some extra documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Dicker committed Sep 13, 2017
1 parent 4747665 commit 14d0561
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 19 deletions.
83 changes: 76 additions & 7 deletions src/prng/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,70 @@ type w32 = w<u32>;
const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

/// A random number generator that uses the ISAAC algorithm[1].
/// A random number generator that uses the ISAAC algorithm.
///
/// The ISAAC algorithm is generally accepted as suitable for
/// cryptographic purposes, but this implementation has not be
/// verified as such. Prefer a generator like `OsRng` that defers to
/// the operating system for cases that need high security.
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
/// the principal bitwise operations employed. It is the most advanced of a
/// series of array based random number generator designed by Robert Jenkins
/// in 1996[1][2].
///
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
/// Although ISAAC is designed to be cryptographically secure, its design is not
/// founded in cryptographic theory. Therefore it is _not recommended for_
/// cryptographic purposes. It is however one of the strongest non-cryptograpic
/// RNGs, and that while still being reasonably fast.
///
/// Where fast random numbers are needed which should still be secure, but where
/// speed is more important than absolute (cryptographic) security (e.g. to
/// initialise hashes in the std library), a generator like ISAAC may be a good
/// choice.
///
/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
/// named ISAAC+[3]. But because the specification is not complete, there is no
/// good implementation, and because the suggested bias may not exist, it is not
/// implemented here.
///
/// ## Overview of the ISAAC algorithm:
/// (in pseudo-code)
///
/// ```text
/// Input: a, b, c, s[256] // state
/// Output: r[256] // results
///
/// mix(a,i) = a ^ a << 13 if i = 0 mod 4
/// a ^ a >> 6 if i = 1 mod 4
/// a ^ a << 2 if i = 2 mod 4
/// a ^ a >> 16 if i = 3 mod 4
///
/// c = c + 1
/// b = b + c
///
/// for i in 0..256 {
/// x = s_[i]
/// a = f(a,i) + s[i+128 mod 256]
/// y = a + b + s[x>>2 mod 256]
/// s[i] = y
/// b = x + s[y>>10 mod 256]
/// r[i] = b
/// }
/// ```
///
/// Numbers are generated in blocks of 256. This means the function above only
/// runs once every 256 times you ask for a next random number. In all other
/// circumstances the last element of the results array is returned.
///
/// ISAAC therefore needs a lot of memory, relative to other non-vrypto RNGs.
/// 2 * 256 * 4 = 2 kb to hold the state and results.
///
/// ## References
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*]
/// (http://burtleburtle.net/bob/rand/isaacafa.html)
///
/// [2]: Bob Jenkins, [*ISAAC and RC4*]
/// (http://burtleburtle.net/bob/rand/isaac.html)
///
/// [3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]
/// (http://eprint.iacr.org/2006/438)

#[derive(Copy)]
pub struct IsaacRng {
rsl: [w32; RAND_SIZE],
Expand Down Expand Up @@ -121,6 +176,20 @@ impl IsaacRng {
}

/// Refills the output buffer (`self.rsl`)
/// See also the pseudocode desciption of the algorithm at the top of this
/// file.
///
/// Optimisations used (similar to the reference implementation):
/// - The loop is unrolled 4 times, once for every constant of mix().
/// - The contents of the main loop are moved to a function `rngstep`, to
/// reduce code duplication.
/// - We use local variables for a and b, which helps with optimisations.
/// - We split the main loop in two, one that operates over 0..128 and one
/// over 128..256. This way we can optimise out the addition and modulus
/// from `s[i+128 mod 256]`.
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
/// arithmetic.
fn isaac(&mut self) {
self.c += w(1);
// abbreviations
Expand Down
70 changes: 61 additions & 9 deletions src/prng/isaac64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The ISAAC random number generator.
//! The ISAAC-64 random number generator.

use core::slice;
use core::iter::repeat;
Expand All @@ -23,16 +23,54 @@ type w64 = w<u64>;
const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

/// A random number generator that uses ISAAC-64[1], the 64-bit
/// variant of the ISAAC algorithm.
/// A random number generator that uses ISAAC-64, the 64-bit variant of the
/// ISAAC algorithm.
///
/// The ISAAC algorithm is generally accepted as suitable for
/// cryptographic purposes, but this implementation has not be
/// verified as such. Prefer a generator like `OsRng` that defers to
/// the operating system for cases that need high security.
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
/// the principal bitwise operations employed. It is the most advanced of a
/// series of array based random number generator designed by Robert Jenkins
/// in 1996[1].
///
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
/// Although ISAAC is designed to be cryptographically secure, its design is not
/// founded in cryptographic theory. Therefore it is _not recommended for_
/// cryptographic purposes. It is however one of the strongest non-cryptograpic
/// RNGs, and that while still being reasonably fast.
///
/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
/// instead of 32-bit, it uses twice as much memory to hold its state and
/// results. Also it uses different constants for shifts and indirect indexing,
/// optimized to give good results for 64bit arithmetic.
///
/// ## Overview of the ISAAC-64 algorithm:
/// (in pseudo-code)
///
/// ```text
/// Input: a, b, c, s[256] // state
/// Output: r[256] // results
///
/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4
/// a ^ a >> 5 if i = 1 mod 4
/// a ^ a << 12 if i = 2 mod 4
/// a ^ a >> 33 if i = 3 mod 4
///
/// c = c + 1
/// b = b + c
///
/// for i in 0..256 {
/// x = s_[i]
/// a = mix(a,i) + s[i+128 mod 256]
/// y = a + b + s[x>>3 mod 256]
/// s[i] = y
/// b = x + s[y>>11 mod 256]
/// r[i] = b
/// }
/// ```
///
/// See for more information the description in rand::prng::IsaacRng.
///
/// [1]: Bob Jenkins, [*ISAAC and RC4*]
/// (http://burtleburtle.net/bob/rand/isaac.html)

#[derive(Copy)]
pub struct Isaac64Rng {
rsl: [w64; RAND_SIZE],
Expand Down Expand Up @@ -122,6 +160,20 @@ impl Isaac64Rng {
}

/// Refills the output buffer (`self.rsl`)
/// See also the pseudocode desciption of the algorithm at the top of this
/// file.
///
/// Optimisations used (similar to the reference implementation):
/// - The loop is unrolled 4 times, once for every constant of mix().
/// - The contents of the main loop are moved to a function `rngstep`, to
/// reduce code duplication.
/// - We use local variables for a and b, which helps with optimisations.
/// - We split the main loop in two, one that operates over 0..128 and one
/// over 128..256. This way we can optimise out the addition and modulus
/// from `s[i+128 mod 256]`.
/// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
/// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
/// arithmetic.
fn isaac64(&mut self) {
self.c += w(1);
// abbreviations
Expand Down
103 changes: 100 additions & 3 deletions src/prng/isaac_word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,105 @@

//! The ISAAC random number generator.

/// Select 32- or 64-bit variant dependent on pointer size.
use core::fmt;
use {Rng, FromRng, SeedableRng};

#[cfg(target_pointer_width = "32")]
#[derive(Copy)]
/// A random number generator that uses the ISAAC or ISAAC-64 algorithm,
/// depending on the pointer size of the target architecture.
///
/// In general a random number generator that internally uses the word size of
/// the target architecture is faster than one that doesn't. Choosing
/// `IsaacWordRng` is therefore often a better choice than `IsaacRng` or
/// `Isaac64Rng`. The others can be a good choice if reproducability across
/// different architectures is desired. `IsaacRng` can also be a better choice
/// if memory usage is an issue, as it uses 2kb of state instead of the 4kb
/// `Isaac64Rng` uses.
///
/// See for an explanation of the algorithm `IsaacRng` and `Isaac64Rng`.
pub struct IsaacWordRng(super::isaac::IsaacRng);

#[cfg(target_pointer_width = "64")]
#[derive(Copy)]
/// A random number generator that uses the ISAAC or ISAAC-64 algorithm,
/// depending on the pointer size of the target architecture.
///
/// In general a random number generator that internally uses the word size of
/// the target architecture is faster than one that doesn't. Choosing
/// `IsaacWordRng` is therefore often a better choice than `IsaacRng` or
/// `Isaac64Rng`. The others can be a good choice if reproducability across
/// different architectures is desired. `IsaacRng` can also be a better choice
/// if memory usage is an issue, as it uses 2kb of state instead of the 4kb
/// `Isaac64Rng` uses.
///
/// See for an explanation of the algorithm `IsaacRng` and `Isaac64Rng`.
pub struct IsaacWordRng(super::isaac64::Isaac64Rng);

impl Clone for IsaacWordRng {
fn clone(&self) -> IsaacWordRng {
*self
}
}

impl Rng for IsaacWordRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
}

#[inline]
fn next_u64(&mut self) -> u64 {
self.0.next_u64()
}
}

impl FromRng for IsaacWordRng {
#[cfg(target_pointer_width = "32")]
fn from_rng<R: Rng+?Sized>(other: &mut R) -> IsaacWordRng {
IsaacWordRng(super::isaac::IsaacRng::from_rng(other))
}

#[cfg(target_pointer_width = "64")]
fn from_rng<R: Rng+?Sized>(other: &mut R) -> IsaacWordRng {
IsaacWordRng(super::isaac64::Isaac64Rng::from_rng(other))
}
}

#[cfg(target_pointer_width = "32")]
pub use prng::isaac::IsaacRng as IsaacWordRng;
impl<'a> SeedableRng<&'a [u32]> for IsaacWordRng {
fn reseed(&mut self, seed: &'a [u32]) {
self.0.reseed(seed)
}

/// Create an ISAAC random number generator with a seed. This can
/// be any length, although the maximum number of elements used is
/// 256 and any more will be silently ignored. A generator
/// constructed with a given seed will generate the same sequence
/// of values as all other generators constructed with that seed.
fn from_seed(seed: &'a [u32]) -> IsaacWordRng {
IsaacWordRng(super::isaac::IsaacRng::from_seed(seed))
}
}

#[cfg(target_pointer_width = "64")]
pub use prng::isaac64::Isaac64Rng as IsaacWordRng;
impl<'a> SeedableRng<&'a [u64]> for IsaacWordRng {
fn reseed(&mut self, seed: &'a [u64]) {
self.0.reseed(seed)
}

/// Create an ISAAC random number generator with a seed. This can
/// be any length, although the maximum number of elements used is
/// 256 and any more will be silently ignored. A generator
/// constructed with a given seed will generate the same sequence
/// of values as all other generators constructed with that seed.
fn from_seed(seed: &'a [u64]) -> IsaacWordRng {
IsaacWordRng(super::isaac64::Isaac64Rng::from_seed(seed))
}
}

impl fmt::Debug for IsaacWordRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IsaacWordRng {{}}")
}
}

0 comments on commit 14d0561

Please sign in to comment.