diff options
Diffstat (limited to 'rand/src/prng')
| -rw-r--r-- | rand/src/prng/chacha.rs | 321 | ||||
| -rw-r--r-- | rand/src/prng/isaac.rs | 328 | ||||
| -rw-r--r-- | rand/src/prng/isaac64.rs | 340 | ||||
| -rw-r--r-- | rand/src/prng/mod.rs | 51 | ||||
| -rw-r--r-- | rand/src/prng/xorshift.rs | 101 | 
5 files changed, 1141 insertions, 0 deletions
| diff --git a/rand/src/prng/chacha.rs b/rand/src/prng/chacha.rs new file mode 100644 index 0000000..a73e8e7 --- /dev/null +++ b/rand/src/prng/chacha.rs @@ -0,0 +1,321 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ChaCha random number generator. + +use core::num::Wrapping as w; +use {Rng, SeedableRng, Rand}; + +#[allow(bad_style)] +type w32 = w<u32>; + +const KEY_WORDS    : usize =  8; // 8 words for the 256-bit key +const STATE_WORDS  : usize = 16; +const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of this writing + +/// A random number generator that uses the ChaCha20 algorithm [1]. +/// +/// The ChaCha algorithm is widely accepted as suitable for +/// cryptographic purposes, but this implementation has not been +/// verified as such. Prefer a generator like `OsRng` that defers to +/// the operating system for cases that need high security. +/// +/// [1]: D. J. Bernstein, [*ChaCha, a variant of +/// Salsa20*](http://cr.yp.to/chacha.html) +#[derive(Copy, Clone, Debug)] +pub struct ChaChaRng { +    buffer:  [w32; STATE_WORDS], // Internal buffer of output +    state:   [w32; STATE_WORDS], // Initial state +    index:   usize,                 // Index into state +} + +static EMPTY: ChaChaRng = ChaChaRng { +    buffer:  [w(0); STATE_WORDS], +    state:   [w(0); STATE_WORDS], +    index:   STATE_WORDS +}; + + +macro_rules! quarter_round{ +    ($a: expr, $b: expr, $c: expr, $d: expr) => {{ +        $a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left(16)); +        $c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left(12)); +        $a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left( 8)); +        $c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left( 7)); +    }} +} + +macro_rules! double_round{ +    ($x: expr) => {{ +        // Column round +        quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]); +        quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]); +        quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]); +        quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]); +        // Diagonal round +        quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]); +        quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]); +        quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]); +        quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]); +    }} +} + +#[inline] +fn core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS]) { +    *output = *input; + +    for _ in 0..CHACHA_ROUNDS / 2 { +        double_round!(output); +    } + +    for i in 0..STATE_WORDS { +        output[i] = output[i] + input[i]; +    } +} + +impl ChaChaRng { + +    /// Create an ChaCha random number generator using the default +    /// fixed key of 8 zero words. +    /// +    /// # Examples +    /// +    /// ```rust +    /// use rand::{Rng, ChaChaRng}; +    /// +    /// let mut ra = ChaChaRng::new_unseeded(); +    /// println!("{:?}", ra.next_u32()); +    /// println!("{:?}", ra.next_u32()); +    /// ``` +    /// +    /// Since this equivalent to a RNG with a fixed seed, repeated executions +    /// of an unseeded RNG will produce the same result. This code sample will +    /// consistently produce: +    /// +    /// - 2917185654 +    /// - 2419978656 +    pub fn new_unseeded() -> ChaChaRng { +        let mut rng = EMPTY; +        rng.init(&[0; KEY_WORDS]); +        rng +    } + +    /// Sets the internal 128-bit ChaCha counter to +    /// a user-provided value. This permits jumping +    /// arbitrarily ahead (or backwards) in the pseudorandom stream. +    /// +    /// Since the nonce words are used to extend the counter to 128 bits, +    /// users wishing to obtain the conventional ChaCha pseudorandom stream +    /// associated with a particular nonce can call this function with +    /// arguments `0, desired_nonce`. +    /// +    /// # Examples +    /// +    /// ```rust +    /// use rand::{Rng, ChaChaRng}; +    /// +    /// let mut ra = ChaChaRng::new_unseeded(); +    /// ra.set_counter(0u64, 1234567890u64); +    /// println!("{:?}", ra.next_u32()); +    /// println!("{:?}", ra.next_u32()); +    /// ``` +    pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) { +        self.state[12] = w((counter_low >>  0) as u32); +        self.state[13] = w((counter_low >> 32) as u32); +        self.state[14] = w((counter_high >>  0) as u32); +        self.state[15] = w((counter_high >> 32) as u32); +        self.index = STATE_WORDS; // force recomputation +    } + +    /// Initializes `self.state` with the appropriate key and constants +    /// +    /// We deviate slightly from the ChaCha specification regarding +    /// the nonce, which is used to extend the counter to 128 bits. +    /// This is provably as strong as the original cipher, though, +    /// since any distinguishing attack on our variant also works +    /// against ChaCha with a chosen-nonce. See the XSalsa20 [1] +    /// security proof for a more involved example of this. +    /// +    /// The modified word layout is: +    /// ```text +    /// constant constant constant constant +    /// key      key      key      key +    /// key      key      key      key +    /// counter  counter  counter  counter +    /// ``` +    /// [1]: Daniel J. Bernstein. [*Extending the Salsa20 +    /// nonce.*](http://cr.yp.to/papers.html#xsalsa) +    fn init(&mut self, key: &[u32; KEY_WORDS]) { +        self.state[0] = w(0x61707865); +        self.state[1] = w(0x3320646E); +        self.state[2] = w(0x79622D32); +        self.state[3] = w(0x6B206574); + +        for i in 0..KEY_WORDS { +            self.state[4+i] = w(key[i]); +        } + +        self.state[12] = w(0); +        self.state[13] = w(0); +        self.state[14] = w(0); +        self.state[15] = w(0); + +        self.index = STATE_WORDS; +    } + +    /// Refill the internal output buffer (`self.buffer`) +    fn update(&mut self) { +        core(&mut self.buffer, &self.state); +        self.index = 0; +        // update 128-bit counter +        self.state[12] = self.state[12] + w(1); +        if self.state[12] != w(0) { return }; +        self.state[13] = self.state[13] + w(1); +        if self.state[13] != w(0) { return }; +        self.state[14] = self.state[14] + w(1); +        if self.state[14] != w(0) { return }; +        self.state[15] = self.state[15] + w(1); +    } +} + +impl Rng for ChaChaRng { +    #[inline] +    fn next_u32(&mut self) -> u32 { +        if self.index == STATE_WORDS { +            self.update(); +        } + +        let value = self.buffer[self.index % STATE_WORDS]; +        self.index += 1; +        value.0 +    } +} + +impl<'a> SeedableRng<&'a [u32]> for ChaChaRng { + +    fn reseed(&mut self, seed: &'a [u32]) { +        // reset state +        self.init(&[0u32; KEY_WORDS]); +        // set key in place +        let key = &mut self.state[4 .. 4+KEY_WORDS]; +        for (k, s) in key.iter_mut().zip(seed.iter()) { +            *k = w(*s); +        } +    } + +    /// Create a ChaCha generator from a seed, +    /// obtained from a variable-length u32 array. +    /// Only up to 8 words are used; if less than 8 +    /// words are used, the remaining are set to zero. +    fn from_seed(seed: &'a [u32]) -> ChaChaRng { +        let mut rng = EMPTY; +        rng.reseed(seed); +        rng +    } +} + +impl Rand for ChaChaRng { +    fn rand<R: Rng>(other: &mut R) -> ChaChaRng { +        let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS]; +        for word in key.iter_mut() { +            *word = other.gen(); +        } +        SeedableRng::from_seed(&key[..]) +    } +} + + +#[cfg(test)] +mod test { +    use {Rng, SeedableRng}; +    use super::ChaChaRng; + +    #[test] +    fn test_rng_rand_seeded() { +        let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>(); +        let mut ra: ChaChaRng = SeedableRng::from_seed(&s[..]); +        let mut rb: ChaChaRng = SeedableRng::from_seed(&s[..]); +        assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), +                                rb.gen_ascii_chars().take(100))); +    } + +    #[test] +    fn test_rng_seeded() { +        let seed : &[_] = &[0,1,2,3,4,5,6,7]; +        let mut ra: ChaChaRng = SeedableRng::from_seed(seed); +        let mut rb: ChaChaRng = SeedableRng::from_seed(seed); +        assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), +                                rb.gen_ascii_chars().take(100))); +    } + +    #[test] +    fn test_rng_reseed() { +        let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>(); +        let mut r: ChaChaRng = SeedableRng::from_seed(&s[..]); +        let string1: String = r.gen_ascii_chars().take(100).collect(); + +        r.reseed(&s); + +        let string2: String = r.gen_ascii_chars().take(100).collect(); +        assert_eq!(string1, string2); +    } + +    #[test] +    fn test_rng_true_values() { +        // Test vectors 1 and 2 from +        // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 +        let seed : &[_] = &[0u32; 8]; +        let mut ra: ChaChaRng = SeedableRng::from_seed(seed); + +        let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>(); +        assert_eq!(v, +                   vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, +                        0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b, +                        0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, +                        0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2)); + +        let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>(); +        assert_eq!(v, +                   vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, +                        0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32, +                        0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, +                        0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b)); + + +        let seed : &[_] = &[0,1,2,3,4,5,6,7]; +        let mut ra: ChaChaRng = SeedableRng::from_seed(seed); + +        // Store the 17*i-th 32-bit word, +        // i.e., the i-th word of the i-th 16-word block +        let mut v : Vec<u32> = Vec::new(); +        for _ in 0..16 { +            v.push(ra.next_u32()); +            for _ in 0..16 { +                ra.next_u32(); +            } +        } + +        assert_eq!(v, +                   vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, +                        0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384, +                        0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, +                        0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4)); +    } + +    #[test] +    fn test_rng_clone() { +        let seed : &[_] = &[0u32; 8]; +        let mut rng: ChaChaRng = SeedableRng::from_seed(seed); +        let mut clone = rng.clone(); +        for _ in 0..16 { +            assert_eq!(rng.next_u64(), clone.next_u64()); +        } +    } +} diff --git a/rand/src/prng/isaac.rs b/rand/src/prng/isaac.rs new file mode 100644 index 0000000..cf5eb67 --- /dev/null +++ b/rand/src/prng/isaac.rs @@ -0,0 +1,328 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC random number generator. + +#![allow(non_camel_case_types)] + +use core::slice; +use core::iter::repeat; +use core::num::Wrapping as w; +use core::fmt; + +use {Rng, SeedableRng, Rand}; + +#[allow(bad_style)] +type w32 = w<u32>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; +const RAND_SIZE_USIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses the ISAAC algorithm[1]. +/// +/// 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. +/// +/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number +/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html) +#[derive(Copy)] +pub struct IsaacRng { +    cnt: u32, +    rsl: [w32; RAND_SIZE_USIZE], +    mem: [w32; RAND_SIZE_USIZE], +    a: w32, +    b: w32, +    c: w32, +} + +static EMPTY: IsaacRng = IsaacRng { +    cnt: 0, +    rsl: [w(0); RAND_SIZE_USIZE], +    mem: [w(0); RAND_SIZE_USIZE], +    a: w(0), b: w(0), c: w(0), +}; + +impl IsaacRng { + +    /// Create an ISAAC random number generator using the default +    /// fixed seed. +    pub fn new_unseeded() -> IsaacRng { +        let mut rng = EMPTY; +        rng.init(false); +        rng +    } + +    /// Initialises `self`. If `use_rsl` is true, then use the current value +    /// of `rsl` as a seed, otherwise construct one algorithmically (not +    /// randomly). +    fn init(&mut self, use_rsl: bool) { +        let mut a = w(0x9e3779b9); +        let mut b = a; +        let mut c = a; +        let mut d = a; +        let mut e = a; +        let mut f = a; +        let mut g = a; +        let mut h = a; + +        macro_rules! mix { +            () => {{ +                a=a^(b<<11); d=d+a; b=b+c; +                b=b^(c>>2);  e=e+b; c=c+d; +                c=c^(d<<8);  f=f+c; d=d+e; +                d=d^(e>>16); g=g+d; e=e+f; +                e=e^(f<<10); h=h+e; f=f+g; +                f=f^(g>>4);  a=a+f; g=g+h; +                g=g^(h<<8);  b=b+g; h=h+a; +                h=h^(a>>9);  c=c+h; a=a+b; +            }} +        } + +        for _ in 0..4 { +            mix!(); +        } + +        if use_rsl { +            macro_rules! memloop { +                ($arr:expr) => {{ +                    for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) { +                        a=a+$arr[i  ]; b=b+$arr[i+1]; +                        c=c+$arr[i+2]; d=d+$arr[i+3]; +                        e=e+$arr[i+4]; f=f+$arr[i+5]; +                        g=g+$arr[i+6]; h=h+$arr[i+7]; +                        mix!(); +                        self.mem[i  ]=a; self.mem[i+1]=b; +                        self.mem[i+2]=c; self.mem[i+3]=d; +                        self.mem[i+4]=e; self.mem[i+5]=f; +                        self.mem[i+6]=g; self.mem[i+7]=h; +                    } +                }} +            } + +            memloop!(self.rsl); +            memloop!(self.mem); +        } else { +            for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) { +                mix!(); +                self.mem[i  ]=a; self.mem[i+1]=b; +                self.mem[i+2]=c; self.mem[i+3]=d; +                self.mem[i+4]=e; self.mem[i+5]=f; +                self.mem[i+6]=g; self.mem[i+7]=h; +            } +        } + +        self.isaac(); +    } + +    /// Refills the output buffer (`self.rsl`) +    #[inline] +    fn isaac(&mut self) { +        self.c = self.c + w(1); +        // abbreviations +        let mut a = self.a; +        let mut b = self.b + self.c; + +        const MIDPOINT: usize = RAND_SIZE_USIZE / 2; + +        macro_rules! ind { +            ($x:expr) => ( self.mem[($x >> 2usize).0 as usize & (RAND_SIZE_USIZE - 1)] ) +        } + +        let r = [(0, MIDPOINT), (MIDPOINT, 0)]; +        for &(mr_offset, m2_offset) in r.iter() { + +            macro_rules! rngstepp { +                ($j:expr, $shift:expr) => {{ +                    let base = $j; +                    let mix = a << $shift; + +                    let x = self.mem[base  + mr_offset]; +                    a = (a ^ mix) + self.mem[base + m2_offset]; +                    let y = ind!(x) + a + b; +                    self.mem[base + mr_offset] = y; + +                    b = ind!(y >> RAND_SIZE_LEN) + x; +                    self.rsl[base + mr_offset] = b; +                }} +            } + +            macro_rules! rngstepn { +                ($j:expr, $shift:expr) => {{ +                    let base = $j; +                    let mix = a >> $shift; + +                    let x = self.mem[base  + mr_offset]; +                    a = (a ^ mix) + self.mem[base + m2_offset]; +                    let y = ind!(x) + a + b; +                    self.mem[base + mr_offset] = y; + +                    b = ind!(y >> RAND_SIZE_LEN) + x; +                    self.rsl[base + mr_offset] = b; +                }} +            } + +            for i in (0..MIDPOINT/4).map(|i| i * 4) { +                rngstepp!(i + 0, 13); +                rngstepn!(i + 1, 6); +                rngstepp!(i + 2, 2); +                rngstepn!(i + 3, 16); +            } +        } + +        self.a = a; +        self.b = b; +        self.cnt = RAND_SIZE; +    } +} + +// Cannot be derived because [u32; 256] does not implement Clone +impl Clone for IsaacRng { +    fn clone(&self) -> IsaacRng { +        *self +    } +} + +impl Rng for IsaacRng { +    #[inline] +    fn next_u32(&mut self) -> u32 { +        if self.cnt == 0 { +            // make some more numbers +            self.isaac(); +        } +        self.cnt -= 1; + +        // self.cnt is at most RAND_SIZE, but that is before the +        // subtraction above. We want to index without bounds +        // checking, but this could lead to incorrect code if someone +        // misrefactors, so we check, sometimes. +        // +        // (Changes here should be reflected in Isaac64Rng.next_u64.) +        debug_assert!(self.cnt < RAND_SIZE); + +        // (the % is cheaply telling the optimiser that we're always +        // in bounds, without unsafe. NB. this is a power of two, so +        // it optimises to a bitwise mask). +        self.rsl[(self.cnt % RAND_SIZE) as usize].0 +    } +} + +impl<'a> SeedableRng<&'a [u32]> for IsaacRng { +    fn reseed(&mut self, seed: &'a [u32]) { +        // make the seed into [seed[0], seed[1], ..., seed[seed.len() +        // - 1], 0, 0, ...], to fill rng.rsl. +        let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u32)); + +        for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) { +            *rsl_elem = w(seed_elem); +        } +        self.cnt = 0; +        self.a = w(0); +        self.b = w(0); +        self.c = w(0); + +        self.init(true); +    } + +    /// 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]) -> IsaacRng { +        let mut rng = EMPTY; +        rng.reseed(seed); +        rng +    } +} + +impl Rand for IsaacRng { +    fn rand<R: Rng>(other: &mut R) -> IsaacRng { +        let mut ret = EMPTY; +        unsafe { +            let ptr = ret.rsl.as_mut_ptr() as *mut u8; + +            let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_USIZE * 4); +            other.fill_bytes(slice); +        } +        ret.cnt = 0; +        ret.a = w(0); +        ret.b = w(0); +        ret.c = w(0); + +        ret.init(true); +        return ret; +    } +} + +impl fmt::Debug for IsaacRng { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        write!(f, "IsaacRng {{}}") +    } +} + +#[cfg(test)] +mod test { +    use {Rng, SeedableRng}; +    use super::IsaacRng; + +    #[test] +    fn test_rng_32_rand_seeded() { +        let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>(); +        let mut ra: IsaacRng = SeedableRng::from_seed(&s[..]); +        let mut rb: IsaacRng = SeedableRng::from_seed(&s[..]); +        assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), +                                rb.gen_ascii_chars().take(100))); +    } + +    #[test] +    fn test_rng_32_seeded() { +        let seed: &[_] = &[1, 23, 456, 7890, 12345]; +        let mut ra: IsaacRng = SeedableRng::from_seed(seed); +        let mut rb: IsaacRng = SeedableRng::from_seed(seed); +        assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), +                                rb.gen_ascii_chars().take(100))); +    } + +    #[test] +    fn test_rng_32_reseed() { +        let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>(); +        let mut r: IsaacRng = SeedableRng::from_seed(&s[..]); +        let string1: String = r.gen_ascii_chars().take(100).collect(); + +        r.reseed(&s[..]); + +        let string2: String = r.gen_ascii_chars().take(100).collect(); +        assert_eq!(string1, string2); +    } + +    #[test] +    fn test_rng_32_true_values() { +        let seed: &[_] = &[1, 23, 456, 7890, 12345]; +        let mut ra: IsaacRng = SeedableRng::from_seed(seed); +        // Regression test that isaac is actually using the above vector +        let v = (0..10).map(|_| ra.next_u32()).collect::<Vec<_>>(); +        assert_eq!(v, +                   vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709, +                        4203127393, 264982119, 2765226902, 2737944514, 3900253796)); + +        let seed: &[_] = &[12345, 67890, 54321, 9876]; +        let mut rb: IsaacRng = SeedableRng::from_seed(seed); +        // skip forward to the 10000th number +        for _ in 0..10000 { rb.next_u32(); } + +        let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>(); +        assert_eq!(v, +                   vec!(3676831399, 3183332890, 2834741178, 3854698763, 2717568474, +                        1576568959, 3507990155, 179069555, 141456972, 2478885421)); +    } +} diff --git a/rand/src/prng/isaac64.rs b/rand/src/prng/isaac64.rs new file mode 100644 index 0000000..b98e3fe --- /dev/null +++ b/rand/src/prng/isaac64.rs @@ -0,0 +1,340 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC-64 random number generator. + +use core::slice; +use core::iter::repeat; +use core::num::Wrapping as w; +use core::fmt; + +use {Rng, SeedableRng, Rand}; + +#[allow(bad_style)] +type w64 = w<u64>; + +const RAND_SIZE_64_LEN: usize = 8; +const RAND_SIZE_64: usize = 1 << RAND_SIZE_64_LEN; + +/// A random number generator that uses ISAAC-64[1], 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. +/// +/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number +/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html) +#[derive(Copy)] +pub struct Isaac64Rng { +    cnt: usize, +    rsl: [w64; RAND_SIZE_64], +    mem: [w64; RAND_SIZE_64], +    a: w64, +    b: w64, +    c: w64, +} + +static EMPTY_64: Isaac64Rng = Isaac64Rng { +    cnt: 0, +    rsl: [w(0); RAND_SIZE_64], +    mem: [w(0); RAND_SIZE_64], +    a: w(0), b: w(0), c: w(0), +}; + +impl Isaac64Rng { +    /// Create a 64-bit ISAAC random number generator using the +    /// default fixed seed. +    pub fn new_unseeded() -> Isaac64Rng { +        let mut rng = EMPTY_64; +        rng.init(false); +        rng +    } + +    /// Initialises `self`. If `use_rsl` is true, then use the current value +    /// of `rsl` as a seed, otherwise construct one algorithmically (not +    /// randomly). +    fn init(&mut self, use_rsl: bool) { +        macro_rules! init { +            ($var:ident) => ( +                let mut $var = w(0x9e3779b97f4a7c13); +            ) +        } +        init!(a); init!(b); init!(c); init!(d); +        init!(e); init!(f); init!(g); init!(h); + +        macro_rules! mix { +            () => {{ +                a=a-e; f=f^(h>>9);  h=h+a; +                b=b-f; g=g^(a<<9);  a=a+b; +                c=c-g; h=h^(b>>23); b=b+c; +                d=d-h; a=a^(c<<15); c=c+d; +                e=e-a; b=b^(d>>14); d=d+e; +                f=f-b; c=c^(e<<20); e=e+f; +                g=g-c; d=d^(f>>17); f=f+g; +                h=h-d; e=e^(g<<14); g=g+h; +            }} +        } + +        for _ in 0..4 { +            mix!(); +        } + +        if use_rsl { +            macro_rules! memloop { +                ($arr:expr) => {{ +                    for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) { +                        a=a+$arr[i  ]; b=b+$arr[i+1]; +                        c=c+$arr[i+2]; d=d+$arr[i+3]; +                        e=e+$arr[i+4]; f=f+$arr[i+5]; +                        g=g+$arr[i+6]; h=h+$arr[i+7]; +                        mix!(); +                        self.mem[i  ]=a; self.mem[i+1]=b; +                        self.mem[i+2]=c; self.mem[i+3]=d; +                        self.mem[i+4]=e; self.mem[i+5]=f; +                        self.mem[i+6]=g; self.mem[i+7]=h; +                    } +                }} +            } + +            memloop!(self.rsl); +            memloop!(self.mem); +        } else { +            for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) { +                mix!(); +                self.mem[i  ]=a; self.mem[i+1]=b; +                self.mem[i+2]=c; self.mem[i+3]=d; +                self.mem[i+4]=e; self.mem[i+5]=f; +                self.mem[i+6]=g; self.mem[i+7]=h; +            } +        } + +        self.isaac64(); +    } + +    /// Refills the output buffer (`self.rsl`) +    fn isaac64(&mut self) { +        self.c = self.c + w(1); +        // abbreviations +        let mut a = self.a; +        let mut b = self.b + self.c; +        const MIDPOINT: usize =  RAND_SIZE_64 / 2; +        const MP_VEC: [(usize, usize); 2] = [(0,MIDPOINT), (MIDPOINT, 0)]; +        macro_rules! ind { +            ($x:expr) => { +                *self.mem.get_unchecked((($x >> 3usize).0 as usize) & (RAND_SIZE_64 - 1)) +            } +        } + +        for &(mr_offset, m2_offset) in MP_VEC.iter() { +            for base in (0..MIDPOINT / 4).map(|i| i * 4) { + +                macro_rules! rngstepp { +                    ($j:expr, $shift:expr) => {{ +                        let base = base + $j; +                        let mix = a ^ (a << $shift); +                        let mix = if $j == 0 {!mix} else {mix}; + +                        unsafe { +                            let x = *self.mem.get_unchecked(base + mr_offset); +                            a = mix + *self.mem.get_unchecked(base + m2_offset); +                            let y = ind!(x) + a + b; +                            *self.mem.get_unchecked_mut(base + mr_offset) = y; + +                            b = ind!(y >> RAND_SIZE_64_LEN) + x; +                            *self.rsl.get_unchecked_mut(base + mr_offset) = b; +                        } +                    }} +                } + +                macro_rules! rngstepn { +                    ($j:expr, $shift:expr) => {{ +                        let base = base + $j; +                        let mix = a ^ (a >> $shift); +                        let mix = if $j == 0 {!mix} else {mix}; + +                        unsafe { +                            let x = *self.mem.get_unchecked(base + mr_offset); +                            a = mix + *self.mem.get_unchecked(base + m2_offset); +                            let y = ind!(x) + a + b; +                            *self.mem.get_unchecked_mut(base + mr_offset) = y; + +                            b = ind!(y >> RAND_SIZE_64_LEN) + x; +                            *self.rsl.get_unchecked_mut(base + mr_offset) = b; +                        } +                    }} +                } + +                rngstepp!(0, 21); +                rngstepn!(1, 5); +                rngstepp!(2, 12); +                rngstepn!(3, 33); +            } +        } + +        self.a = a; +        self.b = b; +        self.cnt = RAND_SIZE_64; +    } +} + +// Cannot be derived because [u32; 256] does not implement Clone +impl Clone for Isaac64Rng { +    fn clone(&self) -> Isaac64Rng { +        *self +    } +} + +impl Rng for Isaac64Rng { +    #[inline] +    fn next_u32(&mut self) -> u32 { +        self.next_u64() as u32 +    } + +    #[inline] +    fn next_u64(&mut self) -> u64 { +        if self.cnt == 0 { +            // make some more numbers +            self.isaac64(); +        } +        self.cnt -= 1; + +        // See corresponding location in IsaacRng.next_u32 for +        // explanation. +        debug_assert!(self.cnt < RAND_SIZE_64); +        self.rsl[(self.cnt % RAND_SIZE_64) as usize].0 +    } +} + +impl<'a> SeedableRng<&'a [u64]> for Isaac64Rng { +    fn reseed(&mut self, seed: &'a [u64]) { +        // make the seed into [seed[0], seed[1], ..., seed[seed.len() +        // - 1], 0, 0, ...], to fill rng.rsl. +        let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u64)); + +        for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) { +            *rsl_elem = w(seed_elem); +        } +        self.cnt = 0; +        self.a = w(0); +        self.b = w(0); +        self.c = w(0); + +        self.init(true); +    } + +    /// 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]) -> Isaac64Rng { +        let mut rng = EMPTY_64; +        rng.reseed(seed); +        rng +    } +} + +impl Rand for Isaac64Rng { +    fn rand<R: Rng>(other: &mut R) -> Isaac64Rng { +        let mut ret = EMPTY_64; +        unsafe { +            let ptr = ret.rsl.as_mut_ptr() as *mut u8; + +            let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_64 * 8); +            other.fill_bytes(slice); +        } +        ret.cnt = 0; +        ret.a = w(0); +        ret.b = w(0); +        ret.c = w(0); + +        ret.init(true); +        return ret; +    } +} + +impl fmt::Debug for Isaac64Rng { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        write!(f, "Isaac64Rng {{}}") +    } +} + +#[cfg(test)] +mod test { +    use {Rng, SeedableRng}; +    use super::Isaac64Rng; + +    #[test] +    fn test_rng_64_rand_seeded() { +        let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>(); +        let mut ra: Isaac64Rng = SeedableRng::from_seed(&s[..]); +        let mut rb: Isaac64Rng = SeedableRng::from_seed(&s[..]); +        assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), +                                rb.gen_ascii_chars().take(100))); +    } + +    #[test] +    fn test_rng_64_seeded() { +        let seed: &[_] = &[1, 23, 456, 7890, 12345]; +        let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); +        let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); +        assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), +                                rb.gen_ascii_chars().take(100))); +    } + +    #[test] +    fn test_rng_64_reseed() { +        let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>(); +        let mut r: Isaac64Rng = SeedableRng::from_seed(&s[..]); +        let string1: String = r.gen_ascii_chars().take(100).collect(); + +        r.reseed(&s[..]); + +        let string2: String = r.gen_ascii_chars().take(100).collect(); +        assert_eq!(string1, string2); +    } + +    #[test] +    fn test_rng_64_true_values() { +        let seed: &[_] = &[1, 23, 456, 7890, 12345]; +        let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); +        // Regression test that isaac is actually using the above vector +        let v = (0..10).map(|_| ra.next_u64()).collect::<Vec<_>>(); +        assert_eq!(v, +                   vec!(547121783600835980, 14377643087320773276, 17351601304698403469, +                        1238879483818134882, 11952566807690396487, 13970131091560099343, +                        4469761996653280935, 15552757044682284409, 6860251611068737823, +                        13722198873481261842)); + +        let seed: &[_] = &[12345, 67890, 54321, 9876]; +        let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); +        // skip forward to the 10000th number +        for _ in 0..10000 { rb.next_u64(); } + +        let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>(); +        assert_eq!(v, +                   vec!(18143823860592706164, 8491801882678285927, 2699425367717515619, +                        17196852593171130876, 2606123525235546165, 15790932315217671084, +                        596345674630742204, 9947027391921273664, 11788097613744130851, +                        10391409374914919106)); +    } + +    #[test] +    fn test_rng_clone() { +        let seed: &[_] = &[1, 23, 456, 7890, 12345]; +        let mut rng: Isaac64Rng = SeedableRng::from_seed(seed); +        let mut clone = rng.clone(); +        for _ in 0..16 { +            assert_eq!(rng.next_u64(), clone.next_u64()); +        } +    } +} diff --git a/rand/src/prng/mod.rs b/rand/src/prng/mod.rs new file mode 100644 index 0000000..ed3e018 --- /dev/null +++ b/rand/src/prng/mod.rs @@ -0,0 +1,51 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Pseudo random number generators are algorithms to produce *apparently +//! random* numbers deterministically, and usually fairly quickly. +//!  +//! So long as the algorithm is computationally secure, is initialised with +//! sufficient entropy (i.e. unknown by an attacker), and its internal state is +//! also protected (unknown to an attacker), the output will also be +//! *computationally secure*. Computationally Secure Pseudo Random Number +//! Generators (CSPRNGs) are thus suitable sources of random numbers for +//! cryptography. There are a couple of gotchas here, however. First, the seed +//! used for initialisation must be unknown. Usually this should be provided by +//! the operating system and should usually be secure, however this may not +//! always be the case (especially soon after startup). Second, user-space +//! memory may be vulnerable, for example when written to swap space, and after +//! forking a child process should reinitialise any user-space PRNGs. For this +//! reason it may be preferable to source random numbers directly from the OS +//! for cryptographic applications. +//!  +//! PRNGs are also widely used for non-cryptographic uses: randomised +//! algorithms, simulations, games. In these applications it is usually not +//! important for numbers to be cryptographically *unguessable*, but even +//! distribution and independence from other samples (from the point of view +//! of someone unaware of the algorithm used, at least) may still be important. +//! Good PRNGs should satisfy these properties, but do not take them for +//! granted; Wikipedia's article on  +//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) +//! provides some background on this topic. +//!  +//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have +//! short periods for some seeds. If one PRNG is seeded from another using the +//! same algorithm, it is possible that both will yield the same sequence of +//! values (with some lag). + +mod chacha; +mod isaac; +mod isaac64; +mod xorshift; + +pub use self::chacha::ChaChaRng; +pub use self::isaac::IsaacRng; +pub use self::isaac64::Isaac64Rng; +pub use self::xorshift::XorShiftRng; diff --git a/rand/src/prng/xorshift.rs b/rand/src/prng/xorshift.rs new file mode 100644 index 0000000..dd367e9 --- /dev/null +++ b/rand/src/prng/xorshift.rs @@ -0,0 +1,101 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Xorshift generators + +use core::num::Wrapping as w; +use {Rng, SeedableRng, Rand}; + +/// An Xorshift[1] random number +/// generator. +/// +/// The Xorshift algorithm is not suitable for cryptographic purposes +/// but is very fast. If you do not know for sure that it fits your +/// requirements, use a more secure one such as `IsaacRng` or `OsRng`. +/// +/// [1]: Marsaglia, George (July 2003). ["Xorshift +/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of +/// Statistical Software*. Vol. 8 (Issue 14). +#[allow(missing_copy_implementations)] +#[derive(Clone, Debug)] +pub struct XorShiftRng { +    x: w<u32>, +    y: w<u32>, +    z: w<u32>, +    w: w<u32>, +} + +impl XorShiftRng { +    /// Creates a new XorShiftRng instance which is not seeded. +    /// +    /// The initial values of this RNG are constants, so all generators created +    /// by this function will yield the same stream of random numbers. It is +    /// highly recommended that this is created through `SeedableRng` instead of +    /// this function +    pub fn new_unseeded() -> XorShiftRng { +        XorShiftRng { +            x: w(0x193a6754), +            y: w(0xa8a7d469), +            z: w(0x97830e05), +            w: w(0x113ba7bb), +        } +    } +} + +impl Rng for XorShiftRng { +    #[inline] +    fn next_u32(&mut self) -> u32 { +        let x = self.x; +        let t = x ^ (x << 11); +        self.x = self.y; +        self.y = self.z; +        self.z = self.w; +        let w_ = self.w; +        self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); +        self.w.0 +    } +} + +impl SeedableRng<[u32; 4]> for XorShiftRng { +    /// Reseed an XorShiftRng. This will panic if `seed` is entirely 0. +    fn reseed(&mut self, seed: [u32; 4]) { +        assert!(!seed.iter().all(|&x| x == 0), +                "XorShiftRng.reseed called with an all zero seed."); + +        self.x = w(seed[0]); +        self.y = w(seed[1]); +        self.z = w(seed[2]); +        self.w = w(seed[3]); +    } + +    /// Create a new XorShiftRng. This will panic if `seed` is entirely 0. +    fn from_seed(seed: [u32; 4]) -> XorShiftRng { +        assert!(!seed.iter().all(|&x| x == 0), +                "XorShiftRng::from_seed called with an all zero seed."); + +        XorShiftRng { +            x: w(seed[0]), +            y: w(seed[1]), +            z: w(seed[2]), +            w: w(seed[3]), +        } +    } +} + +impl Rand for XorShiftRng { +    fn rand<R: Rng>(rng: &mut R) -> XorShiftRng { +        let mut tuple: (u32, u32, u32, u32) = rng.gen(); +        while tuple == (0, 0, 0, 0) { +            tuple = rng.gen(); +        } +        let (x, y, z, w_) = tuple; +        XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) } +    } +} | 
