82 lines
2.2 KiB
C++
82 lines
2.2 KiB
C++
|
/*
|
||
|
* Copyright (C) 2008, Chris Lomont
|
||
|
* Public Domain
|
||
|
*
|
||
|
* http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf
|
||
|
*/
|
||
|
#include <RuntimeInternal.hpp>
|
||
|
#include "WELL.hpp"
|
||
|
#include "mtwister.hpp"
|
||
|
|
||
|
// Redunced seed entropy should not matter to the extent that MT can make up for it.
|
||
|
// WELL is used in the fast rng backend, and i feel as though it would be unreasonable
|
||
|
// to go above UInt64 seeds. For toy purposes, U32 seeds are probably fine. Treat WELL
|
||
|
// like MT without 624 prediction and performance issues.
|
||
|
// Should we look into xorshift soon?
|
||
|
// NOTE: Just to make it clear, the point is that MT entropy should be good enough
|
||
|
// to maintain WELL and xorshift randomness, while acknowledging that reduced seed
|
||
|
// entropy does make it easier to bruteforce especially if the index count is known.
|
||
|
inline static void WELL_SeedRand(WELLRand *rand, AuUInt32 seed)
|
||
|
{
|
||
|
MTRand mtrand = MT_SeedRand(seed);
|
||
|
|
||
|
for (unsigned int i = 0; i < 16; i++)
|
||
|
{
|
||
|
rand->state[i] = MT_NextLong(&mtrand);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new random number generator from a given seed.
|
||
|
*/
|
||
|
WELLRand WELL_SeedRand(AuUInt32 seed)
|
||
|
{
|
||
|
WELLRand rand {};
|
||
|
WELL_SeedRand(&rand, seed);
|
||
|
return rand;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generates a pseudo-randomly generated long.
|
||
|
*/
|
||
|
AuUInt32 WELL_NextLong(WELLRand *rand)
|
||
|
{
|
||
|
AuUInt32 a, b, c, d, ret;
|
||
|
|
||
|
rand->lock.Lock();
|
||
|
a = rand->state[rand->index];
|
||
|
c = rand->state[(rand->index + 13) & 15];
|
||
|
b = a ^ c ^ (a << 16) ^ (c << 15);
|
||
|
c = rand->state[(rand->index + 9) & 15];
|
||
|
c ^= (c >> 11);
|
||
|
a = rand->state[rand->index] = b ^ c;
|
||
|
d = a ^ ((a << 5) & 0xDA442D24UL);
|
||
|
rand->index = (rand->index + 15) & 15;
|
||
|
a = rand->state[rand->index];
|
||
|
rand->state[rand->index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
|
||
|
ret = rand->state[rand->index];
|
||
|
rand->lock.Unlock();
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void WELL_NextBytes(WELLRand *rand, void *in, AuUInt32 length)
|
||
|
{
|
||
|
AuUInt i;
|
||
|
AuUInt8 *base;
|
||
|
|
||
|
i = 0;
|
||
|
base = reinterpret_cast<AuUInt8 *>(in);
|
||
|
|
||
|
for (; i < length; i += 4)
|
||
|
{
|
||
|
AuUInt32 rng = WELL_NextLong(rand);
|
||
|
std::memcpy(base + i, &rng, 4);
|
||
|
}
|
||
|
|
||
|
if (i > length)
|
||
|
{
|
||
|
i -= 4;
|
||
|
AuUInt32 padRng = WELL_NextLong(rand);
|
||
|
std::memcpy(base + i, &padRng, length - i);
|
||
|
}
|
||
|
}
|