What kind of number makes a good seed for a PRNG?

Pseudo-random number generators use complex math to generate random numbers on your computer. These random numbers are used for all sorts of things: simulations, fractals, games, art, and even math experiments. Computers can only do math, which makes generating a random number difficult.

PRNGs need a "seed" number to kick off the math that generates sequences of random numbers. Some PRNGs require a 32bit seed, and some require a 64bit seed. Some PRNGs require one seed, and some require four (or more). It is important to know what type of seed your PRNG needs.

A 32bit number is between 0 and 4.2 billion and a 64bit number is between 0 and 18.4 quintillion. The larger a number is, the more bits are required to store it, and the better a seed it will make. The closer your seed is to the upper end of the number range the better. As a general rule a good seed will be a decimal number with 18 or 19 digits.

12 is a small number and not a good seed, 4611686018427387906 is a big number but still not a great seed. Seeds should not have large sections of zero/one bits. This is why small numbers do not make good seeds. Bits can be visualized by printing the number in binary:

# Horrible
$ perl -E 'printf("%064b\n", 4611686018427387906)'
0100000000000000000000000000000000000000000000000000000000000010

# Bad
$ perl -E 'printf("%064b\n", 17770)'
0000000000000000000000000000000000000000000000000100010101101010

# Poor
$ perl -E 'printf("%064b\n", 2850756010)'
0000000000000000000000000000000010101001111010110001010110101010

# Good
$ perl -E 'printf("%064b\n", 11337502976607798025)'
1001110101010110111001101110001101111000101001000100001100001001

Good seeds should have a roughly even mix of zero and one bits. 9223372036854775808 is a large number and looks promising but it has 63 zeros, and only a single one bit. You can visualize the quality of your seed with seed_quality.pl. Quality above 75% should make for good seed numbers.

Seeds should not be predictable. Do not use dates, times, or phone numbers as they are potentially guessable. Combinations of numbers can be good sources. Process PID, UID, unixtime are good potential sources if they are combined together in a non-predictable way. PID multiplied by UID multiplied by Unixtime is an example of combining values. Memory locations of variables, especially if ASLR is in use is a potentially good source as well.

Hashing numbers, strings, or combinations of numbers can be a good way to generate seeds. Hashing a value with Komihash or xxHash will generate a suitable 64bit number. Hashing a value with SHA256 will generate a 256bit value which can be split into four 64bit values. Hashing functions also do a good job of ensuring the bits are mixed well and do not include large repeating sections.

The best source of seed numbers is directly from your OS. On Linux this is /dev/urandom and on Windows you can interface with the RtlGenRandom API. These are carefully curated sources of true randomness, but they can be slow-ish. Using them as a source for a fast PRNG is best practice.

sub get_64bit_seed {
    open my $urandom, '<:raw', '/dev/urandom' or croak("Couldn't open /dev/urandom: $!");
    sysread($urandom, my $buf, 8) or croak("Couldn't read from csprng: $!");

    return unpack("Q*", $buf);
}
Leave A Reply
All content licensed under the Creative Commons License