Creating random seeds with Java

Random number generators should not be chosen at random. — Donald Knuth
While implementing the Jenetics library, I faced the problem of creating proper seed values for the Randomengines I used. The usual way for doing this, is to take the current time stamp.
To get a feeling about the quality for this kind of seed values, I treated it as special random engine and applied the dieharder test suite to it. As you might expect, the quality of this random engine was disastrous. It didn’t pass a single dieharder test. All of the 114 tests failed.
Since this result was not really satisfying, I was searching for a different entropy source. For Linux system you probably want to choose /dev/random or /dev/urandom as source for your seeds. But this approach is not portable, which was a prerequisite for the Jenetics library. In my second approach I was playing around with the value of the Object.hashCode()function. To get a 64 bit seed value, I concatenated the hashes of two newly created Java objects:
This time, the dieharder returned 28 passed and 86 failed tests. Looks better than the timestamp seed, but 86 failing tests are still not very satisfying. After additional experimentation, I tried to combine the timestamp and the object seeding. The rational behind this was, that the seed shouldn’t rely on a single entropy source.
The code above shows how the timestamp is mixed with the object seed. The mix method was inspired by the mixing step of the lcg64_shift random engine, which has been re-implemented in the LCG64ShiftRandom class. Testing this seed method leads to the following result: 112 passed, 2 weak and 0 failed tests.
Open questions
- How does this method perform on operating systems other than Linux and
- how does this method perform on JMVs other then Java 8.
Conclusion
The statistical performance of the combined seed is better, according to the dieharder test suite, than most of the real random engines I tested, including the default Java Random engine. Using the proposed seed() method is in any case preferable to the simple System.nanoTime() call.
References
- I used the
DieHarderwrapper class for executing the dieharder tests and for creating the test reports. - The following links contain the full dieharder test result: timestamp seed, object hash seed and combined seed.
