From 45afd3e243c075963129faad8ceccc13748553d7 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 15 Oct 2022 16:46:54 +0200 Subject: [PATCH] Replace the rand() which reads from /dev/random with a Mersenne PRNG. Much better now. Also, it is seeded by reading from /dev/random at startup. Not sure if that's the best idea, but we'll see. --- apps/src/init.c | 20 +----------- libs/libc/include/stdlib.h | 2 +- libs/libc/src/init.cpp | 29 +++++++++++++++++ libs/libc/src/rand.cpp | 67 ++++++++++++++++++++++++++------------ 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/apps/src/init.c b/apps/src/init.c index fe54d161..e4b2fad1 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -117,25 +117,7 @@ int main() if (fclose(config) < 0) { perror("fclose"); } - FILE* fp = fopen("/dev/random", "rw"); - if (!fp) - { - perror("fopen"); - return 1; - } - - long int random = 0; - - fread(&random, sizeof(random), 1, fp); - if (ferror(fp)) - { - perror("fread"); - return 1; - } - - fclose(fp); - - printf("\n\nGot random number %ld\n\n", random); + printf("\n\nGot random number %d\n\n", rand()); sleep(2); diff --git a/libs/libc/include/stdlib.h b/libs/libc/include/stdlib.h index 90a5ac48..647a9b04 100644 --- a/libs/libc/include/stdlib.h +++ b/libs/libc/include/stdlib.h @@ -53,7 +53,7 @@ extern "C" /* Returns a random number. */ int rand(void); - /* Does nothing. */ + /* Seeds the random number generator with the specified seed. */ void srand(unsigned int seed); #ifdef __cplusplus diff --git a/libs/libc/src/init.cpp b/libs/libc/src/init.cpp index 279b8d1e..7352cee9 100644 --- a/libs/libc/src/init.cpp +++ b/libs/libc/src/init.cpp @@ -10,6 +10,33 @@ static void terminate_libc() fclose(stderr); } +static void initialize_random() +{ + unsigned int seed = 3735928559U; + + FILE* fp = fopen("/dev/random", "rw"); + if (!fp) + { + errno = 0; + goto failed_to_read_dev_random; + } + + fread(&seed, sizeof(seed), 1, fp); + if (ferror(fp)) + { + errno = 0; + fclose(fp); + goto failed_to_read_dev_random; + } + + fclose(fp); + +failed_to_read_dev_random: + srand(seed); // If we failed, this will be seeded with a known value. Else, it will be seeded with a random value + // from the kernel. + return; +} + static void check_for_file(int fd, FILE** target_stream, const char* path, const char* mode) { if (lseek(fd, 0, SEEK_CUR) < 0) @@ -27,5 +54,7 @@ extern "C" void initialize_libc() { check_for_file(STDOUT_FILENO, &stdout, "/dev/console", "rw"); check_for_file(STDERR_FILENO, &stderr, "/dev/console", "rw"); + + initialize_random(); atexit(terminate_libc); } \ No newline at end of file diff --git a/libs/libc/src/rand.cpp b/libs/libc/src/rand.cpp index eea3ae4e..8398928d 100644 --- a/libs/libc/src/rand.cpp +++ b/libs/libc/src/rand.cpp @@ -1,37 +1,64 @@ #include -#include +#include +#include #include -static FILE* randfp = nullptr; +typedef uint32_t word_t; +#define STATE_SIZE 624 +#define MIDDLE 397 +#define INIT_SHIFT 30 +#define INIT_FACT 1812433253 +#define TWIST_MASK 0x9908b0df +#define SHIFT1 11 +#define MASK1 0xffffffff +#define SHIFT2 7 +#define MASK2 0x9d2c5680 +#define SHIFT3 15 +#define MASK3 0xefc60000 +#define SHIFT4 18 -void close_randfp() +#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 twist() { - fclose(randfp); + 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; } extern "C" { - int rand() // FIXME: This function is a dirty and extremely hacky way to get going, /dev/random should only be used - // for initial seeding, userspace should do their own random calculations. + int rand() { - if (!randfp) + if (index >= STATE_SIZE) { - randfp = fopen("/dev/random", "rw"); - assert(randfp != nullptr); - atexit(close_randfp); + assert(index == STATE_SIZE && "Mersenne generator was never seeded"); + twist(); } - int result; - fread(&result, sizeof(result), 1, randfp); - if (ferror(randfp)) - { - perror("read(randfp)"); - abort(); - } - return result; + + word_t y = state[index]; + y ^= (y >> SHIFT1) & MASK1; + y ^= (y << SHIFT2) & MASK2; + y ^= (y << SHIFT3) & MASK3; + y ^= y >> SHIFT4; + + index++; + return y; } - void srand(unsigned int) + void srand(unsigned int seed) { - return; + index = STATE_SIZE; + state[0] = seed; + for (size_t i = 1; i < STATE_SIZE; i++) + state[i] = (word_t)((INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i); } } \ No newline at end of file