Random: Playing the odds in Ancient Rome
Neil Coffey of Javamex UK offers alternatives to the java.util.Random class, the most commonly used method to generate random numbers in Java.
This class generates “random enough” values, which are described as having an informal level of randomness. Such numbers have a superficial appearance of randomness to an observer, usually a human observer, not a machine. These are considered low-quality random numbers. They should never be used in any security application.
True randomly generated numbers must have the following characteristics:
- Any number is equally likely to be generated on every iteration. This is also known as a uniformly distributed series of numbers.
- The second criterion follows directly: No dependency exists between successive numbers as they are generated.
Alternatives to better match your random needs
Mr. Coffey describes three alternative random number generation methods. Each approach continues to use class java.util.Random, while replacing the underlying algorithm.
The first, called the XORShift generator, produces medium-quality random numbers very quickly, with only a single state variable and very simple code. This method is very well suited to J2ME games.
The next algorithm generates much higher-quality random numbers. It is a combined generator, using two XORShift generators of the sort described above. Mr. Coffey provides the code and explanation for this algorithm. The combined XORShift yields good-quality random numbers. It is suitable for non-gambling games and simulations, although it runs slightly slower than java.util.Random.
A cryptographic quality random number generator should have the following properties:
- It should be impossible to predict prior and future numbers from any number generated;
- The numbers should have no discernible biases;
- The generator has a large period;
- The generator can seed itself at any position within that period with equal probability.
A cryptographically secure random number generator is appropriate for security applications such as producing a web-server session id or picking encryption keys.
Very high-quality random numbers are generated using java.security.SecureRandom as the replacement for java.util.Random. The trade-off in quality versus CPU cycle consumption is hardly surprising. java.security.SecureRandom runs 20 to 30 times slower than any of the other algorithms.
Relative comparison between methods
Here is a very simplified way of understanding the difference between each algorithm. Let’s say that we need to generate a 128-bit encryption key. java.security.SecureRandom actually picks from a pool of 2 raised to the 127th power number of possible keys.
Of course java.util.Random can also be used to generate a 128-bit key. However, the values will be selected from a smaller pool of numbers, on the order of 2 raised to the 47th power number of possible keys. This is because java.util.Random has a much shorter period, equal to 2 raised to the 48th power.
The single XORShift generator method falls between the two, as it has a slightly longer period, of 2 raised to the 64th power. The combined XORShift generator approach extends the period a bit further.
Note than neither java.util.Random nor either of the XORShift generators are seeded randomly. This is why java.security.SecureRandom, with a machine-generated (and much more truly random) random seed, is far superior. The machine-generated random seed is what is called entropy in random number generators.