PHP RFC: RNG fixes and changes
- Version: 1.0
- Date: 2016-05-03
- Author: Leigh T email@example.com
- Status: Implemented (PHP 7.1)
- First Published at: https://wiki.php.net/rfc/rng_fixes
There are several long standing issues with random number generation that should be addressed:
- Incorrect implementations
- Platform-specific outputs
- Poor scaling of bounded outputs
- Insecure usage
Some of these fixes alter the output of the RNG or change the behaviour of functions that depend on them, so it makes sense to perform all of the changes at the same time.
There are several proposals up for discussion.
- Fix the current mt_rand() implementation, with the legacy implementation still available.
- Alias rand() to mt_rand().
- Fix RAND_RANGE for large ranges.
- Replace insecure uses of php_rand() with php_random_bytes()
- Make array_rand() more efficient
Fix mt_rand() implementation
The implementation of
mt_rand() in PHP contains a typo that makes it generate a different sequence of numbers to the original mt19937 implementation. See bug #71152
Statistical analysis suggests that the quality of the output is unaffected.
mt_rand() can be seeded for repeatable sequences the current implementation makes it incompatible with other systems that do use correct implementations. However fixing it also means that the sequence generated for a given seed in PHP will also now be different.
The legacy implementation will be preserved and be selectable with a new `mt_srand(int $seed [, int $mode])` parameter, along with new constants representing the two modes. The default will be the fixed algorithm.
Alias rand() to mt_rand()
rand() uses the system random number generator. The output of this RNG is system dependant and on many systems produces weak random numbers. (See bug #45301)
Aliasing it to
mt_rand() improves the quality of the output and means the same output can be expected for a given seed regardless of platform.
The macro used to scale the output of an RNG between two bounds is insufficient for large ranges. (See bug #45184)
The proposed fix is to concatenate multiple outputs for ranges exceeding 32 bits, and use rejection sampling (the same as used in
random_bytes()) to produce unbiased outputs.
Replace insecure uses of php_rand() with php_random_bytes()
There are several instances where
rand() is used internally in a security sensetive context
- SOAP HTTP auth nonce generation
These instances should all be fixed to use the secure random number generator (even mcrypt which is deprecated)
Make array_rand() more efficient
It has been noted that (array_rand() produces weird and very uneven random distribution). As the above proposals change the output of
array_rand() anyway, we can fix this at the same time.
Backward Incompatible Changes
A call to
mt_srand() with a given seed will produce a different output in the following functions:
Proposed PHP Version(s)
To Existing Extensions
This is covered in the Backward Incompatible Changes section
None, this is a functional change, no changes to opcodes or code generation are required.
MT_RAND_MT19937 (correct implementation mode) MT_RAND_PHP (unofficial implementation mode)
Proposed Voting Choices
Individual votes will be held for the remaining proposals, and since minor BC breaks are introduced they will require a 2/3 majority to pass.
Patches and Tests