#include "bee2/core/mem.h"
#include "bee2/core/prng.h"
#include "bee2/core/u32.h"
#include "bee2/core/util.h"
typedef struct {
u32 x;
u32 y;
u32 z;
union {
u32 u32;
octet block[4];
} r;
size_t reserved;
} prng_combo_st;
static void prngCOMBOStep(prng_combo_st* s)
{
s->r.u32 = s->x * s->x;
s->x = s->y;
s->y = s->r.u32;
s->z = (s->z & 0xFFFF) * 30903 + (s->z >> 16);
s->r.u32 += s->z;
#if (OCTET_ORDER == BIG_ENDIAN)
s->r.u32 = u32Rev(s->r.u32);
#endif
}
size_t prngCOMBO_keep()
{
return sizeof(prng_combo_st);
}
void prngCOMBOStart(void* state, u32 seed)
{
prng_combo_st* s = (prng_combo_st*)state;
ASSERT(memIsValid(s, sizeof(*s)));
s->x = 0xF8B7BB93;
s->y = 0xBEE3B54B;
s->z = 0x1F6B7FBD + seed;
if (s->z)
++s->z;
s->reserved = 0;
}
void prngCOMBOStepR(void* buf, size_t count, void* state)
{
prng_combo_st* s = (prng_combo_st*)state;
ASSERT(memIsValid(buf, count));
ASSERT(memIsValid(s, sizeof(*s)));
if (s->reserved)
{
if (s->reserved >= count)
{
memCopy(buf, s->r.block + 4 - s->reserved, count);
s->reserved -= count;
return;
}
memCopy(buf, s->r.block + 4 - s->reserved, s->reserved);
count -= s->reserved;
buf = (octet*)buf + s->reserved;
s->reserved = 0;
}
while (count >= 4)
{
prngCOMBOStep(s);
memCopy(buf, s->r.block, 4);
buf = (octet*)buf + 4;
count -= 4;
}
if (count)
{
prngCOMBOStep(s);
memCopy(buf, s->r.block, count);
s->reserved = 4 - count;
}
}
typedef struct
{
const octet* seed;
size_t seed_len;
size_t pos;
} prng_echo_st;
size_t prngEcho_keep()
{
return sizeof(prng_echo_st);
}
void prngEchoStart(void* state, const void* seed, size_t seed_len)
{
prng_echo_st* s = (prng_echo_st*)state;
ASSERT(memIsValid(s, sizeof(prng_echo_st)));
ASSERT(seed_len > 0);
ASSERT(memIsValid(seed, seed_len));
s->seed = (const octet*)seed;
s->seed_len = seed_len;
s->pos = 0;
}
void prngEchoStepR(void* buf, size_t count, void* state)
{
prng_echo_st* s = (prng_echo_st*)state;
ASSERT(memIsValid(s, sizeof(prng_echo_st)));
ASSERT(memIsValid(s->seed, s->seed_len));
ASSERT(memIsValid(buf, count));
while (count--)
{
*((octet*)buf) = s->seed[s->pos];
buf = (octet*)buf + 1;
++s->pos;
if (s->pos == s->seed_len)
s->pos = 0;
}
}
typedef struct
{
size_t i;
u16 z[31];
u16 v;
u16 w;
u16 u;
} prng_stb_st;
size_t prngSTB_keep()
{
return sizeof(prng_stb_st);
}
static void _prngSTBClock(prng_stb_st* s)
{
size_t j = (s->i + 10) % 31;
s->v += s->z[s->i];
s->w = (s->w >> 1) | (s->w << 15);
s->w += s->z[(s->i + 20) % 31];
s->u = s->v ^ s->w;
ASSERT(s->z[s->i] < 65257 && s->z[j] < 65257);
if (s->z[s->i] >= s->z[j])
s->z[s->i] -= s->z[j];
else
s->z[s->i] = 65257 - (s->z[j] - s->z[s->i]);
s->i = (s->i + 1) % 31;
}
void prngSTBStart(void* state, const u16 z[31])
{
prng_stb_st* s = (prng_stb_st*)state;
size_t i;
ASSERT(memIsValid(s, sizeof(prng_stb_st)));
ASSERT(memIsNullOrValid(z, 2 * 31));
for (i = 0; i < 31; ++i)
{
s->z[i] = z ? z[i] : (u16)(i + 1);
ASSERT(s->z[i] > 0 && s->z[i] < 65257);
}
s->v = s->w = 0;
s->i = 0;
for (i = 0; i < 256; ++i)
_prngSTBClock(s);
}
void prngSTBStepR(void* buf, size_t count, void* state)
{
register u16 u;
prng_stb_st* s = (prng_stb_st*)state;
ASSERT(memIsValid(s, sizeof(prng_stb_st)));
ASSERT(memIsValid(buf, count));
while (count--)
{
u = s->u;
_prngSTBClock(s);
*((octet*)buf) = (s->u) + u / 255;
buf = (octet*)buf + 1;
}
CLEAN(u);
}