rfc:improve_predictable_prng_random

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:improve_predictable_prng_random [2017/02/02 02:27] – Update RandomState object yohgakirfc:improve_predictable_prng_random [2018/03/01 23:13] (current) – RFC is Under Discussion carusogabriel
Line 1: Line 1:
-====== PHP RFC: Improve predictable PRNG random ======+====== PHP RFC: Improve predictable PRNG random and RNG API======
   * Version: 0.9   * Version: 0.9
   * Date: 2017-02-01   * Date: 2017-02-01
   * Author: Yasuo Ohgaki <yohgaki@ohgaki.net>   * Author: Yasuo Ohgaki <yohgaki@ohgaki.net>
-  * Status: Draft+  * Status: Under Discussion
   * First Published at: http://wiki.php.net/rfc/improve_predictable_prng_random   * First Published at: http://wiki.php.net/rfc/improve_predictable_prng_random
  
Line 14: Line 14:
 <code php> <code php>
 // We need the same random numbers here // We need the same random numbers here
-mt_srand(1234); +srand(1234); 
 for ($i=0; $i < 10; $i++) { for ($i=0; $i < 10; $i++) {
    // Use my PRNG state    // Use my PRNG state
-   $my_rand[] = mt_rand(); +   $my_rand[] = rand(); 
 } }
  
Line 29: Line 29:
 </code> </code>
  
-**This is not limited to specific request that calls mt_srand($some_value), but applies to consecutive requests.**+**Above code worked as it should. PHP 7.1 broke this code.** Similarly, shuffle()/etc are broken by PHP 7.1. 
 + 
 +<code php> 
 +// We need the same random numbers here 
 +mt_srand(1234);  
 +for ($i=0; $i < 10; $i++) { 
 +   // Use my PRNG state 
 +   $my_rand[] = mt_rand();  
 +
 + 
 +// Somewhere later in code AND/OR even other requests 
 + 
 +// We need to shuffle randomly 
 +shuffle($my_random_array); // This is NOT RANDOM at all 
 +</code> 
 + 
 +**These behaviors are not limited to specific request that calls mt_srand($some_value)/srand($some_value), but applies to consecutive requests.**
  
 PHP should have system and user PRNG state to resolve this behavior. PHP should have system and user PRNG state to resolve this behavior.
Line 42: Line 58:
 ==== Rack of Reseeding ==== ==== Rack of Reseeding ====
  
-Reseeding is important for PRNG to mitigate guessed random value. Since MT rand is predictable PRNG, using the same PRNG state allows to guess random value. Current PHP only supports very weak initialization and keeps using the same PRNG state once it is initialized. This behavior makes trivial to guess  MT rand generated random numbers.+Reseeding is important for PRNG to mitigate guessed random value. Since MT rand is predictable PRNG, using the same PRNG state allows to guess next random value easily. Current PHP only supports very weak initialization and keeps using the same PRNG state once it is initialized. This behavior makes trivial to guess  MT rand generated random numbers.
  
 To resolve this issue, PHP should reseed MT rand when state is used certain number of times. To resolve this issue, PHP should reseed MT rand when state is used certain number of times.
Line 48: Line 64:
 ===== Proposal ===== ===== Proposal =====
  
-==== Return PRNG state object from mt_srand()/srand() ====+==== Return PRNG random object (RandomMT) from mt_srand()/srand() ====
  
 <code php> <code php>
-  RandomState mt_srand([int|string $seed]); +  RandomMT mt_srand([int|string $seed]); 
-  RandomState srand([int|string $seed]);+  RandomMT srand([int|string $seed]);
 </code> </code>
  
-Returned RandomeState object is used for PRNG. Unless PRNG state object is specified, functions that use MT rand uses internal system PRNG state. When $seed is string, all bits are used for PRNG state initialization upto MT rand state buffer max. Internal PRNG state uses php_random_bytes() and randomize state.+mt_srand()/srand() returns RandomeMT object, that implements RandomInterface, is used with PRNG functions. Unless PRNG state object is specified, functions that use MT rand uses internal system PRNG state. When $seed is string, all bits are used for PRNG state initialization upto MT rand state buffer max. Internal PRNG state uses php_random_bytes() and randomize state.
  
 Note: srand() is alias of mt_rand(). Python initializes MT rand state by string data like this proposal. Note: srand() is alias of mt_rand(). Python initializes MT rand state by string data like this proposal.
Line 70: Line 86:
  
 <code php> <code php>
-  int mt_rand([RandomState $seed_object]) +  int mt_rand([RandomMT $seed_object]) 
-  int mt_rand(int $min, int $max [, RandomState $seed_object]) +  int mt_rand(int $min, int $max [, RandomMT $seed_object]) 
-  int rand([RandomState $seed_object]) +  int rand([Random $seed_object]) 
-  int rand(int $min, int $max [, RandomState $seed_object]) +  int rand(int $min, int $max [, Random $seed_object]) 
-  bool shuffle(array &$arr [, RandomSatate $seed_object]);+  bool shuffle(array &$arr [, Random $seed_object]);
 </code> </code>
  
 When user initialized PRNG state object is specified, specified state is used to generate random values. When user initialized PRNG state object is specified, specified state is used to generate random values.
  
-==== RandomState object ====+==== Random object and function ====
  
-Create RandomeStateInterface, then implement RPNG specific RandomState objects.+Create RandomeInterface, then implement RNG specific Random objects.
  
 <code php> <code php>
  
-interface RandomStateInterface +interface RandomInterface { 
-    public function seed(); +    public function getInt(int $min = NULL, int $max = NULL); // Int random 
-    public function getCount(); +    public function getBytes(int $length); // Raw bytes 
-    public function getReseedCycle(); +    public function getString(int $length, int $bits = 6); // String [0-9a-zA-Z,-]+ 
-    public function setReseedCycle(int $count);+    public function seed($seed = NULL); // No use with CS RNG, raise exception. 
 +    public function getState(); // Return string representation PRNG state. No use with CS RNG, raise exception. 
 +    public function setState(string $state); // Set PRNG state. No use with CS RNG, raise exception. 
 +    public function getCount(); // No use with CS RNG, raise exception. 
 +    public function getReseedCycle(); // No use with CS RNG, raise exception. 
 +    public function setReseedCycle(int $count); // No use with CS RNG, raise exception.
 } }
  
-class RandomStateMTrand implements RandomStateInterface {+class RandamCS implements RandomIterface { 
 +   // random_*() functions OO API 
 +   // Description omitted, see RandomMT 
 +
 + 
 +// Implement True RNG which may block process when TRNG abstraction function is implemented  
 +class RandamTRNG implements RandomIterface { 
 +   // Description omitted, see RandomMT 
 +
 + 
 +class RandomMT implements RandomInterface {
     private int $count = 0; // Number of this state is used to generate random value     private int $count = 0; // Number of this state is used to generate random value
     private int $reseed = 100; // Max number of count to reseed automatically     private int $reseed = 100; // Max number of count to reseed automatically
     private string $state; // Binary PRNG state     private string $state; // Binary PRNG state
 +    
 +    public function __construct($seed = NULL) {
 +      $this->seed($seed);
 +    }
 +
 +    private reseed() {
 +      $this->count++;
 +      if ($this->reseed && !($this->count % $this->reseed)) {
 +        $this->seed();
 +        $this->count = 1;
 +      }
 +    }
 +    
 +    public function getInt($min = NULL, $max = NULL) {
 +      assert($min <= $max);
 +      $this->reseed();
 +      if ($min && $max) {
 +        return mt_rand($min, $max);
 +      }
 +      if ($min && $min > 0) {
 +        // Return array of random values
 +        while ($min--) {
 +          $ret[] = mt_rand();
 +        }
 +        return $ret;
 +      }
 +      trigger_error('Invalid params');
 +      return FALSE;
 +    }
 +    
 +    public function getBytes(int $length) {
 +      // Return raw random bytes. 3 out of 4 bytes are used not to disclose full PRNG state
 +    }
 +    
 +    public function getString(int $length, int $bits) {
 +      // Return random string as in bin_to_readable() in ext/session.c
 +      // Only 4 to 6 bits out of a byte is used to avoid disclosing raw PRNG state and simplicity.
 +    }    
          
     public function seed($seed = NULL) {     public function seed($seed = NULL) {
Line 103: Line 172:
         // Update state by user seed         // Update state by user seed
         mt_srand($seed);         mt_srand($seed);
 +        $this->reseed = 0;
       } else {       } else {
         // Seed by system generated random value         // Seed by system generated random value
Line 128: Line 198:
    }    }
 } }
 +</code>
 +
 +Random object has getBytes() and getString(). Implement function also.
 +
 +<code php>
 +string mt_rand_bytes(int $length [, RandomMT $rand])
 +string mt_rand_string(int $length [, RandomMT $rand])
 +string rand_bytes(int $length [, Random $rand] ) // Alias of mt_rand_raw() now, but signature differs from MT rand to allow better PRNG in the future.
 +string rand_string(int $length [,int $bits [, Random $rand]]) // Alias of mt_rand_string()
 +string random_string(int $length [,int $bits])
 </code> </code>
  
Line 139: Line 219:
 </code> </code>
  
-uint32_t BG(mt_rand_is_seeded) is used for already seeded flag and counter. Upper 16 bits are used for seeded flag, lower 16 bits are used for counters. Therefore, max reseed count is 2^16.+uint32_t BG(mt_rand_is_seeded) is used for already seeded flag and counter. MSB is used for seeded flag, the rest bits are used for counters. Therefore, max reseed count is 2^31.
  
  
Line 147: Line 227:
 mt_srand()/srand() returned nothing previously. mt_srand()/srand() returned nothing previously.
  
-If users want static random values, they have to use RandomStatus object to get it. Use of mt_srand()/srand() would be rare in general.+If users want static random values, they have to use Random object to get certain random sequence. i.e. Call mt_srand()/srand() for Random object, then use it with functions, rand()/mt_rand()/shuffle()/etc. Use of mt_srand()/srand() would be rare in general.
  
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
Line 169: Line 249:
  
 New New
-  * mt_rand_reseed = 10 for compiled/php.ini-*.+  * mt_rand_reseed = 100 for compiled/php.ini-*.
  
  
Line 189: Line 269:
 ===== Future Scope ===== ===== Future Scope =====
  
-Add object based predictable PRNG API.+Add Random objects as it required
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
rfc/improve_predictable_prng_random.1486002473.txt.gz · Last modified: 2017/09/22 13:28 (external edit)