3v4l.org

run code in 300+ PHP versions simultaneously
<?php /** * Blame Scott Arciszewski of Paragon Initiative Enterprises for this atrocity. * * https://paragonie.com */ class DeterministicRandom { protected $counter; public function __construct(string $seed = '', int $counter = 0) { $this->seed('set', $seed); $this->counter = 0; } private function seed(string $action = 'get', string $data = '') { static $seed = null; if ($action === 'set') { $seed = $data; } elseif ($action === 'get') { return $data; } else { throw new \Error( 'Unknown action' ); } } public function getBytes(int $numBytes): string { return \openssl_encrypt( \str_repeat("\0", $numBytes), 'aes-128-ctr', $this->seed('get'), OPENSSL_RAW_DATA, $this->getNonce($numBytes) ); } public function getInt(int $min, int $max): int { /** * Now that we've verified our weak typing system has given us an integer, * let's validate the logic then we can move forward with generating random * integers along a given range. */ if ($min > $max) { throw new Error( 'Minimum value must be less than or equal to the maximum value' ); } if ($max === $min) { return $min; } /** * Initialize variables to 0 * * We want to store: * $bytes => the number of random bytes we need * $mask => an integer bitmask (for use with the &) operator * so we can minimize the number of discards */ $attempts = $bits = $bytes = $mask = $valueShift = 0; /** * At this point, $range is a positive number greater than 0. It might * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to * a float and we will lose some precision. */ $range = $max - $min; /** * Test for integer overflow: */ if (!is_int($range)) { /** * Still safely calculate wider ranges. * Provided by @CodesInChaos, @oittaa * * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 * * We use ~0 as a mask in this case because it generates all 1s * * @ref https://eval.in/400356 (32-bit) * @ref http://3v4l.org/XX9r5 (64-bit) */ $bytes = PHP_INT_SIZE; $mask = ~0; } else { /** * $bits is effectively ceil(log($range, 2)) without dealing with * type juggling */ while ($range > 0) { if ($bits % 8 === 0) { ++$bytes; } ++$bits; $range >>= 1; $mask = $mask << 1 | 1; } $valueShift = $min; } /** * Now that we have our parameters set up, let's begin generating * random integers until one falls between $min and $max */ do { /** * The rejection probability is at most 0.5, so this corresponds * to a failure probability of 2^-128 for a working RNG */ if ($attempts > 128) { throw new Exception( 'random_int: RNG is broken - too many rejections' ); } /** * Let's grab the necessary number of random bytes */ $randomByteString = $this->getBytes($bytes); if ($randomByteString === false) { throw new Exception( 'Random number generator failure' ); } /** * Let's turn $randomByteString into an integer * * This uses bitwise operators (<< and |) to build an integer * out of the values extracted from ord() * * Example: [9F] | [6D] | [32] | [0C] => * 159 + 27904 + 3276800 + 201326592 => * 204631455 */ $val = 0; for ($i = 0; $i < $bytes; ++$i) { $val |= ord($randomByteString[$i]) << ($i * 8); } /** * Apply mask */ $val &= $mask; $val += $valueShift; ++$attempts; /** * If $val overflows to a floating point number, * ... or is larger than $max, * ... or smaller than $min, * then try again. */ } while (!is_int($val) || $val > $max || $val < $min); return (int) $val; } protected function getNonce(int $increment = 0): string { $nonce = ''; $ctr = $this->counter; while ($ctr > 0) { $nonce = \chr($ctr & 0xFF) . $nonce; $ctr >>= 8; } $this->counter += intdiv($increment + ($increment % 16), 16); return \str_pad($nonce, 16, "\0", STR_PAD_LEFT); } } $seed = str_repeat("\x80", 16); $rnd1 = new DeterministicRandom($seed); $rnd2 = new DeterministicRandom($seed); $out1 = $rnd1->getBytes(16); $out2 = $rnd1->getBytes(16); $out3 = $rnd2->getBytes(32); $int1 = $rnd1->getInt(0, 255); $int2 = $rnd2->getInt(0, 255); var_dump([ bin2hex($out1), bin2hex($out2), bin2hex($out3), $int1, $int2 ]);
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/IkZAM
function name:  (null)
number of ops:  53
compiled vars:  !0 = $seed, !1 = $rnd1, !2 = $rnd2, !3 = $out1, !4 = $out2, !5 = $out3, !6 = $int1, !7 = $int2
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
  179     0  E >   INIT_FCALL                                               'str_repeat'
          1        SEND_VAL                                                 '%80'
          2        SEND_VAL                                                 16
          3        DO_ICALL                                         $8      
          4        ASSIGN                                                   !0, $8
  181     5        NEW                                              $10     'DeterministicRandom'
          6        SEND_VAR_EX                                              !0
          7        DO_FCALL                                      0          
          8        ASSIGN                                                   !1, $10
  182     9        NEW                                              $13     'DeterministicRandom'
         10        SEND_VAR_EX                                              !0
         11        DO_FCALL                                      0          
         12        ASSIGN                                                   !2, $13
  184    13        INIT_METHOD_CALL                                         !1, 'getBytes'
         14        SEND_VAL_EX                                              16
         15        DO_FCALL                                      0  $16     
         16        ASSIGN                                                   !3, $16
  185    17        INIT_METHOD_CALL                                         !1, 'getBytes'
         18        SEND_VAL_EX                                              16
         19        DO_FCALL                                      0  $18     
         20        ASSIGN                                                   !4, $18
  186    21        INIT_METHOD_CALL                                         !2, 'getBytes'
         22        SEND_VAL_EX                                              32
         23        DO_FCALL                                      0  $20     
         24        ASSIGN                                                   !5, $20
  188    25        INIT_METHOD_CALL                                         !1, 'getInt'
         26        SEND_VAL_EX                                              0
         27        SEND_VAL_EX                                              255
         28        DO_FCALL                                      0  $22     
         29        ASSIGN                                                   !6, $22
  189    30        INIT_METHOD_CALL                                         !2, 'getInt'
         31        SEND_VAL_EX                                              0
         32        SEND_VAL_EX                                              255
         33        DO_FCALL                                      0  $24     
         34        ASSIGN                                                   !7, $24
  191    35        INIT_FCALL                                               'var_dump'
  192    36        INIT_FCALL                                               'bin2hex'
         37        SEND_VAR                                                 !3
         38        DO_ICALL                                         $26     
         39        INIT_ARRAY                                       ~27     $26
  193    40        INIT_FCALL                                               'bin2hex'
         41        SEND_VAR                                                 !4
         42        DO_ICALL                                         $28     
         43        ADD_ARRAY_ELEMENT                                ~27     $28
  194    44        INIT_FCALL                                               'bin2hex'
         45        SEND_VAR                                                 !5
         46        DO_ICALL                                         $29     
         47        ADD_ARRAY_ELEMENT                                ~27     $29
  195    48        ADD_ARRAY_ELEMENT                                ~27     !6
  196    49        ADD_ARRAY_ELEMENT                                ~27     !7
         50        SEND_VAL                                                 ~27
         51        DO_ICALL                                                 
  197    52      > RETURN                                                   1

Class DeterministicRandom:
Function __construct:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/IkZAM
function name:  __construct
number of ops:  9
compiled vars:  !0 = $seed, !1 = $counter
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   12     0  E >   RECV_INIT                                        !0      ''
          1        RECV_INIT                                        !1      0
   14     2        INIT_METHOD_CALL                                         'seed'
          3        SEND_VAL_EX                                              'set'
          4        SEND_VAR_EX                                              !0
          5        DO_FCALL                                      0          
   15     6        ASSIGN_OBJ                                               'counter'
          7        OP_DATA                                                  0
   16     8      > RETURN                                                   null

End of function __construct

Function seed:
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 5, Position 2 = 7
Branch analysis from position: 5
1 jumps found. (Code = 42) Position 1 = 15
Branch analysis from position: 15
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 7
2 jumps found. (Code = 43) Position 1 = 9, Position 2 = 11
Branch analysis from position: 9
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 11
1 jumps found. (Code = 108) Position 1 = -2
filename:       /in/IkZAM
function name:  seed
number of ops:  16
compiled vars:  !0 = $action, !1 = $data, !2 = $seed
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   18     0  E >   RECV_INIT                                        !0      'get'
          1        RECV_INIT                                        !1      ''
   20     2        BIND_STATIC                                              !2
   21     3        IS_IDENTICAL                                             !0, 'set'
          4      > JMPZ                                                     ~3, ->7
   22     5    >   ASSIGN                                                   !2, !1
          6      > JMP                                                      ->15
   23     7    >   IS_IDENTICAL                                             !0, 'get'
          8      > JMPZ                                                     ~5, ->11
   24     9    > > RETURN                                                   !1
         10*       JMP                                                      ->15
   26    11    >   NEW                                              $6      'Error'
   27    12        SEND_VAL_EX                                              'Unknown+action'
         13        DO_FCALL                                      0          
         14      > THROW                                         0          $6
   30    15    > > RETURN                                                   null

End of function seed

Function getbytes:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/IkZAM
function name:  getBytes
number of ops:  23
compiled vars:  !0 = $numBytes
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   32     0  E >   RECV                                             !0      
   34     1        INIT_FCALL_BY_NAME                                       'openssl_encrypt'
   35     2        INIT_FCALL                                               'str_repeat'
          3        SEND_VAL                                                 '%00'
          4        SEND_VAR                                                 !0
          5        DO_ICALL                                         $1      
          6        SEND_VAR_NO_REF_EX                                       $1
   36     7        SEND_VAL_EX                                              'aes-128-ctr'
   37     8        INIT_METHOD_CALL                                         'seed'
          9        SEND_VAL                                                 'get'
         10        DO_FCALL                                      0  $2      
         11        SEND_VAR_NO_REF_EX                                       $2
   38    12        FETCH_CONSTANT                                   ~3      'OPENSSL_RAW_DATA'
         13        SEND_VAL_EX                                              ~3
   39    14        INIT_METHOD_CALL                                         'getNonce'
         15        SEND_VAR_EX                                              !0
         16        DO_FCALL                                      0  $4      
         17        SEND_VAR_NO_REF_EX                                       $4
         18        DO_FCALL                                      0  $5      
         19        VERIFY_RETURN_TYPE                                       $5
         20      > RETURN                                                   $5
   41    21*       VERIFY_RETURN_TYPE                                       
         22*     > RETURN                                                   null

End of function getbytes

Function getint:
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 4, Position 2 = 8
Branch analysis from position: 4
1 jumps found. (Code = 108) Position 1 = -2
Branch analysis from position: 8
2 jumps found. (Code = 43) Position 1 = 10, Position 2 = 12
Branch analysis from position: 10
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 12
2 jumps found. (Code = 43) Position 1 = 22, Position 2 = 25
Branch analysis from position: 22
1 jumps found. (Code = 42) Position 1 = 38
Branch analysis from position: 38
2 jumps found. (Code = 43) Position 1 = 40, Position 2 = 44
Branch analysis from position: 40
1 jumps found. (Code = 108) Position 1 = -2
Branch analysis from position: 44
2 jumps found. (Code = 43) Position 1 = 50, Position 2 = 54
Branch analysis from position: 50
1 jumps found. (Code = 108) Position 1 = -2
Branch analysis from position: 54
1 jumps found. (Code = 42) Position 1 = 65
Branch analysis from position: 65
2 jumps found. (Code = 44) Position 1 = 67, Position 2 = 57
Branch analysis from position: 67
2 jumps found. (Code = 47) Position 1 = 73, Position 2 = 75
Branch analysis from position: 73
2 jumps found. (Code = 47) Position 1 = 76, Position 2 = 78
Branch analysis from position: 76
2 jumps found. (Code = 44) Position 1 = 79, Position 2 = 38
Branch analysis from position: 79
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 38
Branch analysis from position: 78
Branch analysis from position: 75
Branch analysis from position: 57
2 jumps found. (Code = 44) Position 1 = 67, Position 2 = 57
Branch analysis from position: 67
Branch analysis from position: 57
Branch analysis from position: 25
1 jumps found. (Code = 42) Position 1 = 35
Branch analysis from position: 35
2 jumps found. (Code = 44) Position 1 = 37, Position 2 = 26
Branch analysis from position: 37
2 jumps found. (Code = 43) Position 1 = 40, Position 2 = 44
Branch analysis from position: 40
Branch analysis from position: 44
Branch analysis from position: 26
2 jumps found. (Code = 43) Position 1 = 29, Position 2 = 30
Branch analysis from position: 29
2 jumps found. (Code = 44) Position 1 = 37, Position 2 = 26
Branch analysis from position: 37
Branch analysis from position: 26
Branch analysis from position: 30
filename:       /in/IkZAM
function name:  getInt
number of ops:  84
compiled vars:  !0 = $min, !1 = $max, !2 = $attempts, !3 = $bits, !4 = $bytes, !5 = $mask, !6 = $valueShift, !7 = $range, !8 = $randomByteString, !9 = $val, !10 = $i
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   43     0  E >   RECV                                             !0      
          1        RECV                                             !1      
   50     2        IS_SMALLER                                               !1, !0
          3      > JMPZ                                                     ~11, ->8
   51     4    >   NEW                                              $12     'Error'
   52     5        SEND_VAL_EX                                              'Minimum+value+must+be+less+than+or+equal+to+the+maximum+value'
          6        DO_FCALL                                      0          
          7      > THROW                                         0          $12
   55     8    >   IS_IDENTICAL                                             !1, !0
          9      > JMPZ                                                     ~14, ->12
   56    10    >   VERIFY_RETURN_TYPE                                       !0
         11      > RETURN                                                   !0
   67    12    >   ASSIGN                                           ~15     !6, 0
         13        ASSIGN                                           ~16     !5, ~15
         14        ASSIGN                                           ~17     !4, ~16
         15        ASSIGN                                           ~18     !3, ~17
         16        ASSIGN                                                   !2, ~18
   74    17        SUB                                              ~20     !1, !0
         18        ASSIGN                                                   !7, ~20
   79    19        TYPE_CHECK                                   16  ~22     !7
         20        BOOL_NOT                                         ~23     ~22
         21      > JMPZ                                                     ~23, ->25
   91    22    >   ASSIGN                                                   !4, 8
   92    23        ASSIGN                                                   !5, -1
         24      > JMP                                                      ->38
   98    25    > > JMP                                                      ->35
   99    26    >   MOD                                              ~26     !3, 8
         27        IS_IDENTICAL                                             ~26, 0
         28      > JMPZ                                                     ~27, ->30
  100    29    >   PRE_INC                                                  !4
  102    30    >   PRE_INC                                                  !3
  103    31        ASSIGN_OP                                     7          !7, 1
  104    32        SL                                               ~31     !5, 1
         33        BW_OR                                            ~32     ~31, 1
         34        ASSIGN                                                   !5, ~32
   98    35    >   IS_SMALLER                                               0, !7
         36      > JMPNZ                                                    ~34, ->26
  106    37    >   ASSIGN                                                   !6, !0
  118    38    >   IS_SMALLER                                               128, !2
         39      > JMPZ                                                     ~36, ->44
  119    40    >   NEW                                              $37     'Exception'
  120    41        SEND_VAL_EX                                              'random_int%3A+RNG+is+broken+-+too+many+rejections'
         42        DO_FCALL                                      0          
         43      > THROW                                         0          $37
  127    44    >   INIT_METHOD_CALL                                         'getBytes'
         45        SEND_VAR_EX                                              !4
         46        DO_FCALL                                      0  $39     
         47        ASSIGN                                                   !8, $39
  128    48        TYPE_CHECK                                    4          !8
         49      > JMPZ                                                     ~41, ->54
  129    50    >   NEW                                              $42     'Exception'
  130    51        SEND_VAL_EX                                              'Random+number+generator+failure'
         52        DO_FCALL                                      0          
         53      > THROW                                         0          $42
  144    54    >   ASSIGN                                                   !9, 0
  145    55        ASSIGN                                                   !10, 0
         56      > JMP                                                      ->65
  146    57    >   INIT_FCALL                                               'ord'
         58        FETCH_DIM_R                                      ~46     !8, !10
         59        SEND_VAL                                                 ~46
         60        DO_ICALL                                         $47     
         61        MUL                                              ~48     !10, 8
         62        SL                                               ~49     $47, ~48
         63        ASSIGN_OP                                     9          !9, ~49
  145    64        PRE_INC                                                  !10
         65    >   IS_SMALLER                                               !10, !4
         66      > JMPNZ                                                    ~52, ->57
  152    67    >   ASSIGN_OP                                    10          !9, !5
  153    68        ASSIGN_OP                                     1          !9, !6
  155    69        PRE_INC                                                  !2
  162    70        TYPE_CHECK                                   16  ~56     !9
         71        BOOL_NOT                                         ~57     ~56
         72      > JMPNZ_EX                                         ~57     ~57, ->75
         73    >   IS_SMALLER                                       ~58     !1, !9
         74        BOOL                                             ~57     ~58
         75    > > JMPNZ_EX                                         ~57     ~57, ->78
         76    >   IS_SMALLER                                       ~59     !9, !0
         77        BOOL                                             ~57     ~59
         78    > > JMPNZ                                                    ~57, ->38
  163    79    >   CAST                                          4  ~60     !9
         80        VERIFY_RETURN_TYPE                                       ~60
         81      > RETURN                                                   ~60
  164    82*       VERIFY_RETURN_TYPE                                       
         83*     > RETURN                                                   null

End of function getint

Function getnonce:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 42) Position 1 = 12
Branch analysis from position: 12
2 jumps found. (Code = 44) Position 1 = 14, Position 2 = 5
Branch analysis from position: 14
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 5
2 jumps found. (Code = 44) Position 1 = 14, Position 2 = 5
Branch analysis from position: 14
Branch analysis from position: 5
filename:       /in/IkZAM
function name:  getNonce
number of ops:  32
compiled vars:  !0 = $increment, !1 = $nonce, !2 = $ctr
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
  166     0  E >   RECV_INIT                                        !0      0
  168     1        ASSIGN                                                   !1, ''
  169     2        FETCH_OBJ_R                                      ~4      'counter'
          3        ASSIGN                                                   !2, ~4
  170     4      > JMP                                                      ->12
  171     5    >   INIT_FCALL                                               'chr'
          6        BW_AND                                           ~6      !2, 255
          7        SEND_VAL                                                 ~6
          8        DO_ICALL                                         $7      
          9        CONCAT                                           ~8      $7, !1
         10        ASSIGN                                                   !1, ~8
  172    11        ASSIGN_OP                                     7          !2, 8
  170    12    >   IS_SMALLER                                               0, !2
         13      > JMPNZ                                                    ~11, ->5
  174    14    >   INIT_FCALL                                               'intdiv'
         15        MOD                                              ~13     !0, 16
         16        ADD                                              ~14     !0, ~13
         17        SEND_VAL                                                 ~14
         18        SEND_VAL                                                 16
         19        DO_ICALL                                         $15     
         20        ASSIGN_OBJ_OP                                 1          'counter'
         21        OP_DATA                                                  $15
  175    22        INIT_FCALL                                               'str_pad'
         23        SEND_VAR                                                 !1
         24        SEND_VAL                                                 16
         25        SEND_VAL                                                 '%00'
         26        SEND_VAL                                                 0
         27        DO_ICALL                                         $16     
         28        VERIFY_RETURN_TYPE                                       $16
         29      > RETURN                                                   $16
  176    30*       VERIFY_RETURN_TYPE                                       
         31*     > RETURN                                                   null

End of function getnonce

End of class DeterministicRandom.

Generated using Vulcan Logic Dumper, using php 8.0.0


preferences:
176.95 ms | 1416 KiB | 27 Q