diff --git a/include/kernel/util.h b/include/kernel/util.h index 4ffed8b..2e07422 100644 --- a/include/kernel/util.h +++ b/include/kernel/util.h @@ -61,6 +61,7 @@ extern uint64_t host_to_little_u64(uint64_t v); extern uint64_t big_to_host_u64(uint64_t v); extern uint64_t little_to_host_u64(uint64_t v); +extern void init_random(uint64_t seed); extern bool fill_random(void *buffer, unsigned int size); #ifdef __cplusplus diff --git a/util/random.c b/util/random.c index 8066477..a37b7ff 100644 --- a/util/random.c +++ b/util/random.c @@ -1,35 +1,81 @@ #include -static unsigned int random_seed = 53455346; +typedef uint64_t word_t; +#define STATE_SIZE 312 +#define MIDDLE 156 +#define INIT_SHIFT 62 +#define TWIST_MASK 0xb5026f5aa96619e9 +#define INIT_FACT 6364136223846793005 +#define SHIFT1 29 +#define MASK1 0x5555555555555555 +#define SHIFT2 17 +#define MASK2 0x71d67fffeda60000 +#define SHIFT3 37 +#define MASK3 0xfff7eee000000000 +#define SHIFT4 43 + +#define LOWER_MASK 0x7fffffff +#define UPPER_MASK (~(word_t)LOWER_MASK) +static word_t state[STATE_SIZE]; +static size_t index = STATE_SIZE + 1; + +static void seed(word_t s) +{ + index = STATE_SIZE; + state[0] = s; + for (size_t i = 1; i < STATE_SIZE; i++) { + state[i] = (INIT_FACT + * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + + i; + } +} + +static void twist(void) +{ + for (size_t i = 0; i < STATE_SIZE; i++) { + word_t x = (state[i] & UPPER_MASK) + | (state[(i + 1) % STATE_SIZE] & LOWER_MASK); + x = (x >> 1) ^ (x & 1 ? TWIST_MASK : 0); + state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x; + } + + index = 0; +} + +static word_t mt_random(void) +{ + if (index >= STATE_SIZE) { + twist(); + } + + word_t y = state[index]; + y ^= (y >> SHIFT1) & MASK1; + y ^= (y << SHIFT2) & MASK2; + y ^= (y << SHIFT3) & MASK3; + y ^= y >> SHIFT4; + + index++; + return y; +} + +void init_random(uint64_t seedvalue) +{ + seed(seedvalue); +} bool fill_random(void *p, unsigned int size) { - unsigned char *buffer = p; + unsigned char *dst = p; + uint64_t w = mt_random(); + unsigned char *src = (unsigned char *)&w; - if (!buffer || !size) { - return false; - } + for (size_t i = 0, j = 0; i < size; i++, j++) { + dst[i] = src[j]; - for (uint32_t i = 0; i < size; i++) { - uint32_t next = random_seed; - uint32_t result; - - next *= 1103515245; - next += 12345; - result = (uint32_t)(next / 65536) % 2048; - - next *= 1103515245; - next += 12345; - result <<= 10; - result ^= (uint32_t)(next / 65536) % 1024; - - next *= 1103515245; - next += 12345; - result <<= 10; - result ^= (uint32_t)(next / 65536) % 1024; - random_seed = next; - - buffer[i] = (uint8_t)(result % 256); + if (j == (sizeof w) - 1) { + w = mt_random(); + j = 0; + } } return true;