rust/lfprng/src/lib.rs
author nemo
Tue, 30 Apr 2019 09:36:13 -0400
changeset 14859 8d65728c4ed0
parent 14152 5acfdf49742d
child 15115 de32299de704
permissions -rw-r--r--
Backed out changeset 13589d529899 So, we only disabled this on the release branch in r29d614a5c9eb due to having discovered it JUST before release. We should fix it properly in default...

pub struct LaggedFibonacciPRNG {
    circular_buffer: [u32; 64],
    index: usize,
}

impl LaggedFibonacciPRNG {
    pub fn new(init_values: &[u8]) -> Self {
        let mut buf = [0xa98765 + 68; 64];

        for i in 0..std::cmp::min(init_values.len(), 54) {
            buf[i] = init_values[i] as u32;
        }

        let mut prng = Self {
            circular_buffer: buf,
            index: 54,
        };

        for _i in 0..2048 {
            prng.get_next();
        }

        prng
    }

    #[inline]
    fn get_next(&mut self) -> u32 {
        self.index = (self.index + 1) & 0x3f;
        self.circular_buffer[self.index] = (self.circular_buffer[(self.index + 40) & 0x3f]
            + self.circular_buffer[(self.index + 9) & 0x3f])
            & 0x7fffffff;

        self.circular_buffer[self.index]
    }

    #[inline]
    pub fn get_random(&mut self, modulo: u32) -> u32 {
        self.get_next();
        self.get_next() % modulo
    }

    #[inline]
    pub fn add_randomness(&mut self, value: u32) {
        self.index = (self.index + 1) & 0x3f;
        self.circular_buffer[self.index] ^= value;
    }
}

impl Iterator for LaggedFibonacciPRNG {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        self.get_next();
        Some(self.get_next())
    }
}

#[cfg(test)]
#[test]
fn compatibility() {
    let mut prng = LaggedFibonacciPRNG::new("{052e2aee-ce41-4720-97bd-559a413bf866}".as_bytes());

    assert_eq!(prng.get_random(1000), 418);
    assert_eq!(prng.get_random(1000000), 554064);
    assert_eq!(prng.get_random(0xffffffff), 239515837);

    prng.add_randomness(123);

    for i in 0..=100000 {
        prng.get_random(2);
    }

    assert_eq!(prng.get_random(0xffffffff), 525333582);
}