WSJT-X/lib/init_random_seed.c
Bill Somerville 93b2f4164a Improve the randomness of the srand seed generator
XOR:ing the time since epoch in seconds with the PID fails for processes
started every second since the PID and time increment in step regularly in
this scenario and therefore give identical seeds. Thanks to Steve K9AN for
spotting this subtle flaw.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6294 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
2015-12-18 17:32:56 +00:00

83 lines
1.8 KiB
C

#include "init_random_seed.h"
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
/* basic PRNG to use for improving the basic seed selection */
static unsigned lcg (uint64_t seed)
{
if (0 ==seed)
{
seed = UINT64_C(104729);
}
else
{
seed %= UINT64_C(4294967296);
}
seed = (seed * UINT64_C(279470273)) % UINT64_C(4294967291);
return seed % UINT64_MAX;
}
/* Generate a good PRNG seed value */
void init_random_seed(void)
{
unsigned seed = 0u;
int have_seed = 0;
// try /dev/urandom for an initial seed
int random_source;
if ((random_source = open ("/dev/urandom", O_RDONLY)) >= 0)
{
size_t random_data_length = 0;
have_seed = -1;
while (random_data_length < sizeof seed)
{
ssize_t result = read (random_source, &seed + random_data_length, (sizeof seed) - random_data_length);
if (result < 0)
{
// error, unable to read /dev/random
have_seed = 0;
}
random_data_length += result;
}
close (random_source);
}
if (!have_seed)
{
// fallback to combining the time and PID in a fairly random way
pid_t pid = getpid ();
struct timeval tv;
gettimeofday (&tv, NULL);
seed = (unsigned)(((unsigned)pid << 16)
^ (unsigned)pid
^ (unsigned)tv.tv_sec
^ (unsigned)tv.tv_usec);
seed = lcg (seed);
}
srand (seed);
}
#ifdef TEST
#include <stdio.h>
int main (int argc, char * argv[])
{
init_random_seed ();
int i, j;
int r[10][4];
for (i = 0; i < 10; ++i)
{
for (j = 0; j < 4; ++j)
{
printf ("%10d ", rand ());
}
printf ("\n");
}
return 0;
}
#endif