rfc:rng_extension
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:rng_extension [2021/06/25 23:32] – without internal zeriyoshi | rfc:rng_extension [2021/09/03 13:53] – fix: missing CSPRNG functions. zeriyoshi | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Add Random Extension ====== | + | ====== PHP RFC: Random Extension |
- | * Version: | + | * Version: |
- | * Date: 2021-05-18 | + | * Date: 2021-09-02 |
* Author: Go Kudo < | * Author: Go Kudo < | ||
* Status: Under Discussion | * Status: Under Discussion | ||
- | * Implementation: | + | * Implementation: |
* First Published at: http:// | * First Published at: http:// | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | PHP is currently having problems with RNG reproducibility. | ||
- | PHP' | + | Currently, |
- | But, these functions still store the state in the global state of PHP and are not easily reproducible. Look at the following example. | + | The first is that there are many different implementations. Historically, the random number implementations have been separated into lcg.c, rand.c, mt_rand.c random.c respectively, |
+ | |||
+ | Second, the pseudo-random number generator makes use of global state. If a random number is consumed at an unexpected time, the reproducibility | ||
<code php> | <code php> | ||
Line 27: | Line 28: | ||
</ | </ | ||
- | As mentioned above, the reproducibility | + | Reproducibility |
In addition, the fiber extension was introduced in PHP 8.1. This makes it more difficult to keep track of the execution order. However, this problem has existed since the introduced of Generator. | In addition, the fiber extension was introduced in PHP 8.1. This makes it more difficult to keep track of the execution order. However, this problem has existed since the introduced of Generator. | ||
Line 43: | Line 44: | ||
===== Proposal ===== | ===== Proposal ===== | ||
- | Implement and bundled Random extension into PHP. | ||
- | The phpstub for the whole extension is as follows: | + | Clean up the implementation, |
- | <code php> | + | All of the following functions will be moved to the newly created Random extension. |
- | <?php | + | |
- | /** @generate-class-entries | + | |
- | /** @generate-function-entries | + | |
+ | | ||
+ | * mt_srand() | ||
+ | | ||
+ | * random_int() | ||
+ | | ||
- | namespace Random\NumberGenerator | + | At the same time, the following internal APIs will also be relocated. If you want to use them, you can simply include ext/random/random.h. |
- | { | + | |
- | interface RandomNumberGenerator | + | |
- | { | + | |
- | | + | |
- | public function generate(): int; | + | |
- | } | + | |
- | class XorShift128Plus implements RandomNumberGenerator | + | * php_random_int_throw() |
- | { | + | * php_random_int_silent() |
- | /** @tentative-return-type | + | * php_combined_lcg() |
- | | + | |
+ | | ||
+ | * php_mt_rand_range() | ||
+ | * php_mt_rand_common() | ||
+ | * php_srand() | ||
+ | * php_rand() | ||
+ | * php_random_bytes() | ||
+ | * php_random_int() | ||
- | /** | + | The following PHP constants will now be provided by the Random extension |
- | * @tentative-return-type | + | |
- | * @internal | + | |
- | */ | + | |
- | public function generate(): int {} | + | |
- | /** @tentative-return-type */ | + | |
- | public function __serialize(): | + | |
- | /** @tentative-return-type */ | + | To solve the scope problem, the following classes will be added |
- | public function __unserialize(array $data): void {} | + | |
- | } | + | |
- | | + | * Random |
- | { | + | * Random\NumberGenrator abstract class |
- | /** | + | * Random\NumberGenerator\XorShift128Plus |
- | | + | * Random\NumberGenerator\MT19937 class |
- | | + | * Random\NumberGenerator\Secure class |
- | | + | |
- | public function __construct(? | + | |
- | /** | + | The Random |
- | * @implementation-alias | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function generate(): int {} | + | |
- | /** | + | |
- | | + | * getBytes() |
- | | + | * shuffleArray() |
- | | + | * shuffleString() |
- | public function __serialize(): array {} | + | |
- | /** | + | The Random class accepts an instance that inherits from Random\NumberGenerator |
- | * @implementation-alias | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function __unserialize(array $data): void {} | + | |
- | } | + | |
- | | + | This class is final and cannot be cloned, but it can be serialized. |
- | { | + | This is to prevent $rng from being copied by reference to a property and causing unintended behavior. |
- | /** @tentative-return-type */ | + | |
- | public function __construct() {} | + | |
- | /** | + | The serializability depends on the serializability of the contained $rng. |
- | * @implementation-alias Random\NumberGenerator\XorShift128Plus:: | + | |
- | * @tentative-return-type | + | |
- | */ | + | |
- | public function generate(): int {} | + | |
- | } | + | |
- | } | + | |
- | namespace | + | <code php> |
+ | final class Random | ||
{ | { | ||
- | | + | |
- | { | + | |
- | /** @tentative-return-type */ | + | |
- | public function nextInt(): int; | + | |
- | /** @tentative-return-type */ | + | public function __construct(? |
- | public function getInt(int $min, int $max): int; | + | |
- | + | | |
- | /** @tentative-return-type */ | + | public function getBytes(int $length): string |
- | | + | public function shuffleArray(array $array): array {} |
- | + | public function shuffleString(string $string): string | |
- | /** @tentative-return-type */ | + | |
- | | + | |
- | + | ||
- | /** @tentative-return-type */ | + | |
- | | + | |
- | | + | |
- | | + | public function __serialize(): |
- | { | + | public function __unserialize(array $data): void {} |
- | // FIXME: stub generator (gen_stub.php) does not supported. | + | |
- | // private Random\NumberGenerator\RandomNumberGenerator $rng; | + | |
- | private mixed $rng; | + | |
- | + | ||
- | public function __construct(? | + | |
- | public function getNumberGenerator(): | + | |
- | public function nextInt(): int {} | + | |
- | public function getInt(int $min, int $max): int {} | + | |
- | public function getBytes(int $length): string {} | + | |
- | public function shuffleArray(array $array): array {} | + | |
- | public function shuffleString(string $string): string {} | + | |
- | | + | |
- | public function __unserialize(array $data): void {} | + | |
- | | + | |
} | } | ||
</ | </ | ||
- | Each RNG is implemented as a class in the Random\NumberGenerator | + | The Random\NumberGenerator |
- | The bundled RNGs are as follows: | + | <code php> |
+ | namespace Random; | ||
- | * Random\NumberGenerator\XorShift128Plus: | + | abstract class NumberGenerator |
- | * Random\NumberGenerator\MT19937: | + | { |
- | * Random\NumberGenerator\Secure: | + | abstract public function generate(): int {} |
+ | } | ||
+ | </code> | ||
- | Random | + | By defining a class that extends |
- | However, when used XorShift128+ | + | |
- | + | ||
- | Secure is practically equivalent to random_int() and random_bytes(), | + | |
- | + | ||
- | This class also supports RNGs defined in userland. It can be used by passing an instance of a class that implements the RandomNumberGenerator interface provided | + | |
<code php> | <code php> | ||
- | + | class UserDefinedRNG | |
- | class UserDefinedRNG | + | |
{ | { | ||
protected int $current = 0; | protected int $current = 0; | ||
- | | + | |
public function generate(): int | public function generate(): int | ||
{ | { | ||
Line 185: | Line 139: | ||
} | } | ||
- | function foobar(Random $random): void { | + | function foobar(Random\NumberGenerator |
for ($i = 0; $i < 9; $i++) { | for ($i = 0; $i < 9; $i++) { | ||
- | echo $random->nextInt(); | + | echo $numberGenerator->generate(); |
} | } | ||
} | } | ||
- | foobar(new Random(new UserDefinedRNG())); // Results: 123456789 | + | foobar(new UserDefinedRNG()); |
</ | </ | ||
- | Also, as with MT, various alternative APIs using Random class will be provided. | + | It is also useful when you want to use a random number sequence with a fixed result, such as in testing. |
- | <code c> | + | The Random class creates and uses an instance of the default random number generator, Random\NumberGenerator\XorShift128Plus, |
- | /* similar php_mt_rand() */ | + | |
- | uint64_t php_random_next(php_random *php_random, bool shift); | + | |
- | /* similar php_mt_rand_range() */ | + | XorShift128Plus is an efficient, high-quality algorithm used in modern browsers and other applications. This algorithm is capable of generating a wider range of random numbers in a 64-bit environment. In a 32-bit environment, |
- | zend_long php_random_range(php_random *php_random, zend_long | + | |
- | /* similar php_array_data_shuffle() */ | + | The Random\NumberGenerator\MT19937 |
- | void php_random_array_data_shuffle(php_random *php_random, | + | |
- | + | ||
- | /* similar php_string_shuffle() */ | + | |
- | void php_random_string_shuffle(php_random *php_random, | + | |
- | </ | + | |
- | + | ||
- | The Random class can be serialized using the standard PHP serialization mechanism. But, if the $rng member | + | |
<code php> | <code php> | ||
- | // serialize | + | $seed = 1234; |
- | $foo = new Random(new Random\Numbergenerator\XorShift128Plus()); | + | |
- | for ($i = 0; $i < 10; $i++) { $foo-> | + | |
- | var_dump(unserialize(serialize($foo))-> | + | |
- | // can't serialize | + | $mt = new Random\NumberGenerator\MT19937($seed); |
- | $foo = new Random(new Random\Numbergenerator\Secure()); | + | mt_srand($seed); |
- | for ($i = 0; $i < 10; $i++) { $foo-> | + | var_dump(mt_rand() === ($mt->generate() >> 1)); // true |
- | var_dump(unserialize(serialize($foo))-> | + | |
</ | </ | ||
- | It is not possible to clone the Random | + | The following NumberGenerator |
- | <code php> | + | * Random\NumberGenerator\XorShift128Plus |
- | $foo = new Random(); | + | * Random\NumberGenerator\MT19937 |
+ | | ||
- | // can't direct clone | + | Also, a new internal API will be implemented. |
- | // $bar = clone $foo; | + | |
- | // safe | + | * php_random_ng_next() |
- | $bar = new Random(clone $foo-> | + | * php_random_ng_range() |
- | </ | + | * php_random_ng_array_data_shuffle() |
+ | * php_random_ng_string_shuffle() | ||
- | Using this feature, the first example | + | A Stub showing these implementations |
- | <code php> | + | * [[https://github.com/php/php-src/ |
- | echo foo(1234, function (): void {}) . PHP_EOL; | + | |
- | echo foo(1234, function (): void { mt_rand(); }) . PHP_EOL; | + | |
- | + | ||
- | function foo(int $seed, callable $bar): int { | + | |
- | $random = new Random(new Random\NumberGenerator\MT19937($seed)); | + | |
- | $result = $random-> | + | |
- | $bar(); | + | |
- | $result += $random-> | + | |
- | return $result; | + | |
- | } | + | |
- | </code> | + | |
===== Future Scope ===== | ===== Future Scope ===== | ||
- | This RFC will be the basis for making | + | This proposal is just a first step to improve |
- | By first accepted | + | If this proposal is approved, I will then propose |
- | The Random class can also be used when new features are implemented that use random numbers. This has the effect | + | * Replace |
- | + | * Replace random_bytes() with random_bytes() for random numbers used in shuffle(), str_shuffle(), and array_rand(). | |
- | More in the future, we can consider doing away with functions such as mt_srand(). These functions are simple and convenient, but they may unintentionally create implementations that depend on global scope. | + | * Deprecate srand() and mt_srand() (step by step) |
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
- | The following class name will no longer be available: | ||
- | - " | + | The code that includes the following header file needs to be changed to ext/ |
- | | + | |
- | | + | |
- | | + | * ext/ |
- | | + | * ext/ |
- | | + | * ext/ |
+ | |||
+ | The following class names have been reserved and will no longer be available | ||
+ | |||
+ | * " | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | 8.1 | + | 8.2 |
- | + | ||
- | ===== FAQ ===== | + | |
- | ==== ==== | + | |
===== RFC Impact ===== | ===== RFC Impact ===== | ||
Line 305: | Line 239: | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | * https:// | + | * https:// |
rfc/rng_extension.txt · Last modified: 2022/08/01 16:52 by timwolla