/* This class implements a 160-bit pseudo-random number generator. * This generator combines David Jone's JKISS generator with an alternating * step generator utilizing a 32-bit Galois m_lfsr as a gate. * It passes all tests in TestU01 BigCrush. * This software is derived from LibRNG, a public domain pseudo-random number * library. (http://www.github.com/bhickey/librng) */ #include "AppHdr.h" #include "asg.h" static AsgKISS asg_rng[2]; uint32_t AsgKISS::get_uint32() { m_lcg = (314527869 * m_lcg + 1234567); m_lfsr = (m_lfsr >> 1) ^ (-(int32_t)(m_lfsr & 1U) & 0xD0000001U); if (m_lfsr & 1) { m_xorshift ^= m_xorshift << 5; m_xorshift ^= m_xorshift >> 7; m_xorshift ^= m_xorshift << 22; } else { uint64_t t = 4294584393ULL * m_mwcm + m_mwcc; m_mwcc = t >> 32; m_mwcm = t; } return m_lcg + m_mwcm + m_xorshift; } AsgKISS::AsgKISS() { m_lcg = 12345678; m_mwcm = 43219876; m_mwcc = 6543217; m_xorshift = 987654321; m_lfsr = 76543210; } AsgKISS::AsgKISS(uint32_t init_key[], int key_length) { m_lcg = (key_length > 0 ? init_key[0] : 12345678); m_mwcm = (key_length > 1 ? init_key[1] : 43219876); m_mwcc = (key_length > 2 ? init_key[2] : 6543217); m_xorshift = (key_length > 3 ? init_key[3] : 987654321); m_lfsr = (key_length > 4 ? init_key[4] : 7654321); // m_lfsr must not be set to zero. if (!m_lfsr) { m_lfsr = 7654321; while (!(m_lfsr = get_uint32())); } } uint32_t get_uint32(int generator) { ASSERT(generator >= 0); ASSERT((size_t) generator < ARRAYSZ(asg_rng)); return asg_rng[generator].get_uint32(); } void seed_asg(uint32_t seed_array[], int seed_len) { { const AsgKISS seeded(seed_array, seed_len); asg_rng[0] = seeded; } // Use the just seeded RNG to initialize the rest. for (size_t i = 1; i < ARRAYSZ(asg_rng); ++i) { uint32_t key[5]; for (size_t j = 0; j < ARRAYSZ(key); ++j) key[j] = asg_rng[0].get_uint32(); const AsgKISS seeded(key, ARRAYSZ(key)); asg_rng[i] = seeded; } }