#include #include #include #include #ifdef LINUX #include #include #endif #include #include "rng.h" #include "log.h" /* Mersenne twister state. */ static uint32_t MT[624]; static uint32_t mt_y; static int mt_pos = 0; /* Current number. */ static uint32_t rng_timeEntropy(void); /* Mersenne twister. */ static void mt_initArray(uint32_t seed); static void mt_genArray(void); static uint32_t mt_getInt(void); void rng_init(void) { uint32_t i; int need_init; need_init = 1; /* Initialize by default. */ #ifdef LINUX int fd; fd = open("/dev/urandom", O_RDONLY); /* /dev/urandom is better then time seed. */ if(fd != -1) { i = sizeof(uint32_t)*624; if(read(fd, &MT, i) == (ssize_t)i) need_init = 0; else i = rng_timeEntropy(); close(fd); } else i = rng_timeEntropy(); #else i = rng_timeEntropy(); #endif if(need_init) mt_initArray(i); for(i = 0; i < 10; i++) /* Generate numbers to get away from poor initial values. */ mt_genArray(); } /* Use the time as source of entropy. */ static uint32_t rng_timeEntropy(void) { int i; #ifdef WIN32 struct _timeb tb; _ftime(&tb); i = tb.time * 1000 + tb.millitm; #else struct timeval tv; gettimeofday(&tv, NULL); i = tv.tv_sec * 1000000 + tv.tv_usec; #endif return i; } /* Generates the initial mersenne twister based on seed. */ static void mt_initArray(uint32_t seed) { int i; MT[0] = seed; for(i = 1; i < 624; i++) MT[i] = 1812433253 * (MT[i-1] ^ (((MT[i-1])) + i) >> 30); mt_pos = 0; } /* Generate an array of numbers. */ static void mt_genArray(void) { int i; for(i = 0; i < 624; i++) { mt_y = (MT[i] & 0x80000000) + ((MT[i] % 624) & 0x7FFFFFFF); if(mt_y % 2) /* Odd. */ MT[i] = (MT[(i+397) % 624] ^ (mt_y >> 1)) ^ 2567483615; else /* Even. */ MT[i] = MT[(i+397) % 624] ^ (mt_y >> 1); } mt_pos = 0; } /* Get the next int. */ static uint32_t mt_getInt(void) { if(mt_pos >= 624) mt_genArray(); mt_y = MT[mt_pos++]; mt_y ^= mt_y >> 11; mt_y ^= (mt_y << 7) & 2636928640; mt_y ^= (mt_y << 15) & 4022730752; mt_y ^= (mt_y >> 18); return mt_y; } /* Return a random int. */ unsigned int randint(void) { return mt_getInt(); } /* Return a random double. */ static double m_div = (double)(0xFFFFFFFF); double randfp(void) { double m = (double)mt_getInt(); return m / m_div; }