wp/wp-includes/sodium_compat/src/Core32/Int32.php
changeset 9 177826044cd9
child 19 3d72ae0968f4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * Class ParagonIE_Sodium_Core32_Int32
       
     5  *
       
     6  * Encapsulates a 32-bit integer.
       
     7  *
       
     8  * These are immutable. It always returns a new instance.
       
     9  */
       
    10 class ParagonIE_Sodium_Core32_Int32
       
    11 {
       
    12     /**
       
    13      * @var array<int, int> - two 16-bit integers
       
    14      *
       
    15      * 0 is the higher 16 bits
       
    16      * 1 is the lower 16 bits
       
    17      */
       
    18     public $limbs = array(0, 0);
       
    19 
       
    20     /**
       
    21      * @var int
       
    22      */
       
    23     public $overflow = 0;
       
    24 
       
    25     /**
       
    26      * @var bool
       
    27      */
       
    28     public $unsignedInt = false;
       
    29 
       
    30     /**
       
    31      * ParagonIE_Sodium_Core32_Int32 constructor.
       
    32      * @param array $array
       
    33      * @param bool $unsignedInt
       
    34      */
       
    35     public function __construct($array = array(0, 0), $unsignedInt = false)
       
    36     {
       
    37         $this->limbs = array(
       
    38             (int) $array[0],
       
    39             (int) $array[1]
       
    40         );
       
    41         $this->overflow = 0;
       
    42         $this->unsignedInt = $unsignedInt;
       
    43     }
       
    44 
       
    45     /**
       
    46      * Adds two int32 objects
       
    47      *
       
    48      * @param ParagonIE_Sodium_Core32_Int32 $addend
       
    49      * @return ParagonIE_Sodium_Core32_Int32
       
    50      */
       
    51     public function addInt32(ParagonIE_Sodium_Core32_Int32 $addend)
       
    52     {
       
    53         $i0 = $this->limbs[0];
       
    54         $i1 = $this->limbs[1];
       
    55         $j0 = $addend->limbs[0];
       
    56         $j1 = $addend->limbs[1];
       
    57 
       
    58         $r1 = $i1 + ($j1 & 0xffff);
       
    59         $carry = $r1 >> 16;
       
    60 
       
    61         $r0 = $i0 + ($j0 & 0xffff) + $carry;
       
    62         $carry = $r0 >> 16;
       
    63 
       
    64         $r0 &= 0xffff;
       
    65         $r1 &= 0xffff;
       
    66 
       
    67         $return = new ParagonIE_Sodium_Core32_Int32(
       
    68             array($r0, $r1)
       
    69         );
       
    70         $return->overflow = $carry;
       
    71         $return->unsignedInt = $this->unsignedInt;
       
    72         return $return;
       
    73     }
       
    74 
       
    75     /**
       
    76      * Adds a normal integer to an int32 object
       
    77      *
       
    78      * @param int $int
       
    79      * @return ParagonIE_Sodium_Core32_Int32
       
    80      * @throws SodiumException
       
    81      * @throws TypeError
       
    82      */
       
    83     public function addInt($int)
       
    84     {
       
    85         ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
       
    86         /** @var int $int */
       
    87         $int = (int) $int;
       
    88 
       
    89         $int = (int) $int;
       
    90 
       
    91         $i0 = $this->limbs[0];
       
    92         $i1 = $this->limbs[1];
       
    93 
       
    94         $r1 = $i1 + ($int & 0xffff);
       
    95         $carry = $r1 >> 16;
       
    96 
       
    97         $r0 = $i0 + (($int >> 16) & 0xffff) + $carry;
       
    98         $carry = $r0 >> 16;
       
    99         $r0 &= 0xffff;
       
   100         $r1 &= 0xffff;
       
   101         $return = new ParagonIE_Sodium_Core32_Int32(
       
   102             array($r0, $r1)
       
   103         );
       
   104         $return->overflow = $carry;
       
   105         $return->unsignedInt = $this->unsignedInt;
       
   106         return $return;
       
   107     }
       
   108 
       
   109     /**
       
   110      * @param int $b
       
   111      * @return int
       
   112      */
       
   113     public function compareInt($b = 0)
       
   114     {
       
   115         $gt = 0;
       
   116         $eq = 1;
       
   117 
       
   118         $i = 2;
       
   119         $j = 0;
       
   120         while ($i > 0) {
       
   121             --$i;
       
   122             /** @var int $x1 */
       
   123             $x1 = $this->limbs[$i];
       
   124             /** @var int $x2 */
       
   125             $x2 = ($b >> ($j << 4)) & 0xffff;
       
   126             /** @var int $gt */
       
   127             $gt |= (($x2 - $x1) >> 8) & $eq;
       
   128             /** @var int $eq */
       
   129             $eq &= (($x2 ^ $x1) - 1) >> 8;
       
   130         }
       
   131         return ($gt + $gt - $eq) + 1;
       
   132     }
       
   133 
       
   134     /**
       
   135      * @param int $m
       
   136      * @return ParagonIE_Sodium_Core32_Int32
       
   137      */
       
   138     public function mask($m = 0)
       
   139     {
       
   140         /** @var int $hi */
       
   141         $hi = ($m >> 16) & 0xffff;
       
   142         /** @var int $lo */
       
   143         $lo = ($m & 0xffff);
       
   144         return new ParagonIE_Sodium_Core32_Int32(
       
   145             array(
       
   146                 (int) ($this->limbs[0] & $hi),
       
   147                 (int) ($this->limbs[1] & $lo)
       
   148             ),
       
   149             $this->unsignedInt
       
   150         );
       
   151     }
       
   152 
       
   153     /**
       
   154      * @param array<int, int> $a
       
   155      * @param array<int, int> $b
       
   156      * @param int $baseLog2
       
   157      * @return array<int, int>
       
   158      */
       
   159     public function multiplyLong(array $a, array $b, $baseLog2 = 16)
       
   160     {
       
   161         $a_l = count($a);
       
   162         $b_l = count($b);
       
   163         /** @var array<int, int> $r */
       
   164         $r = array_fill(0, $a_l + $b_l + 1, 0);
       
   165         $base = 1 << $baseLog2;
       
   166         for ($i = 0; $i < $a_l; ++$i) {
       
   167             $a_i = $a[$i];
       
   168             for ($j = 0; $j < $a_l; ++$j) {
       
   169                 $b_j = $b[$j];
       
   170                 $product = ($a_i * $b_j) + $r[$i + $j];
       
   171                 $carry = ($product >> $baseLog2 & 0xffff);
       
   172                 $r[$i + $j] = ($product - (int) ($carry * $base)) & 0xffff;
       
   173                 $r[$i + $j + 1] += $carry;
       
   174             }
       
   175         }
       
   176         return array_slice($r, 0, 5);
       
   177     }
       
   178 
       
   179     /**
       
   180      * @param int $int
       
   181      * @return ParagonIE_Sodium_Core32_Int32
       
   182      */
       
   183     public function mulIntFast($int)
       
   184     {
       
   185         // Handle negative numbers
       
   186         $aNeg = ($this->limbs[0] >> 15) & 1;
       
   187         $bNeg = ($int >> 31) & 1;
       
   188         $a = array_reverse($this->limbs);
       
   189         $b = array(
       
   190             $int & 0xffff,
       
   191             ($int >> 16) & 0xffff
       
   192         );
       
   193         if ($aNeg) {
       
   194             for ($i = 0; $i < 2; ++$i) {
       
   195                 $a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
       
   196             }
       
   197             ++$a[0];
       
   198         }
       
   199         if ($bNeg) {
       
   200             for ($i = 0; $i < 2; ++$i) {
       
   201                 $b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
       
   202             }
       
   203             ++$b[0];
       
   204         }
       
   205         // Multiply
       
   206         $res = $this->multiplyLong($a, $b);
       
   207 
       
   208         // Re-apply negation to results
       
   209         if ($aNeg !== $bNeg) {
       
   210             for ($i = 0; $i < 2; ++$i) {
       
   211                 $res[$i] = (0xffff ^ $res[$i]) & 0xffff;
       
   212             }
       
   213             // Handle integer overflow
       
   214             $c = 1;
       
   215             for ($i = 0; $i < 2; ++$i) {
       
   216                 $res[$i] += $c;
       
   217                 $c = $res[$i] >> 16;
       
   218                 $res[$i] &= 0xffff;
       
   219             }
       
   220         }
       
   221 
       
   222         // Return our values
       
   223         $return = new ParagonIE_Sodium_Core32_Int32();
       
   224         $return->limbs = array(
       
   225             $res[1] & 0xffff,
       
   226             $res[0] & 0xffff
       
   227         );
       
   228         if (count($res) > 2) {
       
   229             $return->overflow = $res[2] & 0xffff;
       
   230         }
       
   231         $return->unsignedInt = $this->unsignedInt;
       
   232         return $return;
       
   233     }
       
   234 
       
   235     /**
       
   236      * @param ParagonIE_Sodium_Core32_Int32 $right
       
   237      * @return ParagonIE_Sodium_Core32_Int32
       
   238      */
       
   239     public function mulInt32Fast(ParagonIE_Sodium_Core32_Int32 $right)
       
   240     {
       
   241         $aNeg = ($this->limbs[0] >> 15) & 1;
       
   242         $bNeg = ($right->limbs[0] >> 15) & 1;
       
   243 
       
   244         $a = array_reverse($this->limbs);
       
   245         $b = array_reverse($right->limbs);
       
   246         if ($aNeg) {
       
   247             for ($i = 0; $i < 2; ++$i) {
       
   248                 $a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
       
   249             }
       
   250             ++$a[0];
       
   251         }
       
   252         if ($bNeg) {
       
   253             for ($i = 0; $i < 2; ++$i) {
       
   254                 $b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
       
   255             }
       
   256             ++$b[0];
       
   257         }
       
   258         $res = $this->multiplyLong($a, $b);
       
   259         if ($aNeg !== $bNeg) {
       
   260             if ($aNeg !== $bNeg) {
       
   261                 for ($i = 0; $i < 2; ++$i) {
       
   262                     $res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
       
   263                 }
       
   264                 $c = 1;
       
   265                 for ($i = 0; $i < 2; ++$i) {
       
   266                     $res[$i] += $c;
       
   267                     $c = $res[$i] >> 16;
       
   268                     $res[$i] &= 0xffff;
       
   269                 }
       
   270             }
       
   271         }
       
   272         $return = new ParagonIE_Sodium_Core32_Int32();
       
   273         $return->limbs = array(
       
   274             $res[1] & 0xffff,
       
   275             $res[0] & 0xffff
       
   276         );
       
   277         if (count($res) > 2) {
       
   278             $return->overflow = $res[2];
       
   279         }
       
   280         return $return;
       
   281     }
       
   282 
       
   283     /**
       
   284      * @param int $int
       
   285      * @param int $size
       
   286      * @return ParagonIE_Sodium_Core32_Int32
       
   287      * @throws SodiumException
       
   288      * @throws TypeError
       
   289      */
       
   290     public function mulInt($int = 0, $size = 0)
       
   291     {
       
   292         ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
       
   293         ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
       
   294         if (ParagonIE_Sodium_Compat::$fastMult) {
       
   295             return $this->mulIntFast((int) $int);
       
   296         }
       
   297         /** @var int $int */
       
   298         $int = (int) $int;
       
   299         /** @var int $size */
       
   300         $size = (int) $size;
       
   301 
       
   302         if (!$size) {
       
   303             $size = 31;
       
   304         }
       
   305         /** @var int $size */
       
   306 
       
   307         $a = clone $this;
       
   308         $return = new ParagonIE_Sodium_Core32_Int32();
       
   309         $return->unsignedInt = $this->unsignedInt;
       
   310 
       
   311         // Initialize:
       
   312         $ret0 = 0;
       
   313         $ret1 = 0;
       
   314         $a0 = $a->limbs[0];
       
   315         $a1 = $a->limbs[1];
       
   316 
       
   317         /** @var int $size */
       
   318         /** @var int $i */
       
   319         for ($i = $size; $i >= 0; --$i) {
       
   320             $m = (int) (-($int & 1));
       
   321             $x0 = $a0 & $m;
       
   322             $x1 = $a1 & $m;
       
   323 
       
   324             $ret1 += $x1;
       
   325             $c = $ret1 >> 16;
       
   326 
       
   327             $ret0 += $x0 + $c;
       
   328 
       
   329             $ret0 &= 0xffff;
       
   330             $ret1 &= 0xffff;
       
   331 
       
   332             $a1 = ($a1 << 1);
       
   333             $x1 = $a1 >> 16;
       
   334             $a0 = ($a0 << 1) | $x1;
       
   335             $a0 &= 0xffff;
       
   336             $a1 &= 0xffff;
       
   337             $int >>= 1;
       
   338         }
       
   339         $return->limbs[0] = $ret0;
       
   340         $return->limbs[1] = $ret1;
       
   341         return $return;
       
   342     }
       
   343 
       
   344     /**
       
   345      * @param ParagonIE_Sodium_Core32_Int32 $int
       
   346      * @param int $size
       
   347      * @return ParagonIE_Sodium_Core32_Int32
       
   348      * @throws SodiumException
       
   349      * @throws TypeError
       
   350      */
       
   351     public function mulInt32(ParagonIE_Sodium_Core32_Int32 $int, $size = 0)
       
   352     {
       
   353         ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
       
   354         if (ParagonIE_Sodium_Compat::$fastMult) {
       
   355             return $this->mulInt32Fast($int);
       
   356         }
       
   357         if (!$size) {
       
   358             $size = 31;
       
   359         }
       
   360         /** @var int $size */
       
   361 
       
   362         $a = clone $this;
       
   363         $b = clone $int;
       
   364         $return = new ParagonIE_Sodium_Core32_Int32();
       
   365         $return->unsignedInt = $this->unsignedInt;
       
   366 
       
   367         // Initialize:
       
   368         $ret0 = 0;
       
   369         $ret1 = 0;
       
   370         $a0 = $a->limbs[0];
       
   371         $a1 = $a->limbs[1];
       
   372         $b0 = $b->limbs[0];
       
   373         $b1 = $b->limbs[1];
       
   374 
       
   375         /** @var int $size */
       
   376         /** @var int $i */
       
   377         for ($i = $size; $i >= 0; --$i) {
       
   378             $m = (int) (-($b1 & 1));
       
   379             $x0 = $a0 & $m;
       
   380             $x1 = $a1 & $m;
       
   381 
       
   382             $ret1 += $x1;
       
   383             $c = $ret1 >> 16;
       
   384 
       
   385             $ret0 += $x0 + $c;
       
   386 
       
   387             $ret0 &= 0xffff;
       
   388             $ret1 &= 0xffff;
       
   389 
       
   390             $a1 = ($a1 << 1);
       
   391             $x1 = $a1 >> 16;
       
   392             $a0 = ($a0 << 1) | $x1;
       
   393             $a0 &= 0xffff;
       
   394             $a1 &= 0xffff;
       
   395 
       
   396             $x0 = ($b0 & 1) << 16;
       
   397             $b0 = ($b0 >> 1);
       
   398             $b1 = (($b1 | $x0) >> 1);
       
   399 
       
   400             $b0 &= 0xffff;
       
   401             $b1 &= 0xffff;
       
   402 
       
   403         }
       
   404         $return->limbs[0] = $ret0;
       
   405         $return->limbs[1] = $ret1;
       
   406 
       
   407         return $return;
       
   408     }
       
   409 
       
   410     /**
       
   411      * OR this 32-bit integer with another.
       
   412      *
       
   413      * @param ParagonIE_Sodium_Core32_Int32 $b
       
   414      * @return ParagonIE_Sodium_Core32_Int32
       
   415      */
       
   416     public function orInt32(ParagonIE_Sodium_Core32_Int32 $b)
       
   417     {
       
   418         $return = new ParagonIE_Sodium_Core32_Int32();
       
   419         $return->unsignedInt = $this->unsignedInt;
       
   420         $return->limbs = array(
       
   421             (int) ($this->limbs[0] | $b->limbs[0]),
       
   422             (int) ($this->limbs[1] | $b->limbs[1])
       
   423         );
       
   424         /** @var int overflow */
       
   425         $return->overflow = $this->overflow | $b->overflow;
       
   426         return $return;
       
   427     }
       
   428 
       
   429     /**
       
   430      * @param int $b
       
   431      * @return bool
       
   432      */
       
   433     public function isGreaterThan($b = 0)
       
   434     {
       
   435         return $this->compareInt($b) > 0;
       
   436     }
       
   437 
       
   438     /**
       
   439      * @param int $b
       
   440      * @return bool
       
   441      */
       
   442     public function isLessThanInt($b = 0)
       
   443     {
       
   444         return $this->compareInt($b) < 0;
       
   445     }
       
   446 
       
   447     /**
       
   448      * @param int $c
       
   449      * @return ParagonIE_Sodium_Core32_Int32
       
   450      * @throws SodiumException
       
   451      * @throws TypeError
       
   452      * @psalm-suppress MixedArrayAccess
       
   453      */
       
   454     public function rotateLeft($c = 0)
       
   455     {
       
   456         ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
       
   457         /** @var int $c */
       
   458         $c = (int) $c;
       
   459 
       
   460         $return = new ParagonIE_Sodium_Core32_Int32();
       
   461         $return->unsignedInt = $this->unsignedInt;
       
   462         $c &= 31;
       
   463         if ($c === 0) {
       
   464             // NOP, but we want a copy.
       
   465             $return->limbs = $this->limbs;
       
   466         } else {
       
   467             /** @var int $c */
       
   468 
       
   469             /** @var int $idx_shift */
       
   470             $idx_shift = ($c >> 4) & 1;
       
   471 
       
   472             /** @var int $sub_shift */
       
   473             $sub_shift = $c & 15;
       
   474 
       
   475             /** @var array<int, int> $limbs */
       
   476             $limbs =& $return->limbs;
       
   477 
       
   478             /** @var array<int, int> $myLimbs */
       
   479             $myLimbs =& $this->limbs;
       
   480 
       
   481             for ($i = 1; $i >= 0; --$i) {
       
   482                 /** @var int $j */
       
   483                 $j = ($i + $idx_shift) & 1;
       
   484                 /** @var int $k */
       
   485                 $k = ($i + $idx_shift + 1) & 1;
       
   486                 $limbs[$i] = (int) (
       
   487                     (
       
   488                         ((int) ($myLimbs[$j]) << $sub_shift)
       
   489                             |
       
   490                         ((int) ($myLimbs[$k]) >> (16 - $sub_shift))
       
   491                     ) & 0xffff
       
   492                 );
       
   493             }
       
   494         }
       
   495         return $return;
       
   496     }
       
   497 
       
   498     /**
       
   499      * Rotate to the right
       
   500      *
       
   501      * @param int $c
       
   502      * @return ParagonIE_Sodium_Core32_Int32
       
   503      * @throws SodiumException
       
   504      * @throws TypeError
       
   505      * @psalm-suppress MixedArrayAccess
       
   506      */
       
   507     public function rotateRight($c = 0)
       
   508     {
       
   509         ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
       
   510         /** @var int $c */
       
   511         $c = (int) $c;
       
   512 
       
   513         $return = new ParagonIE_Sodium_Core32_Int32();
       
   514         $return->unsignedInt = $this->unsignedInt;
       
   515         $c &= 31;
       
   516         /** @var int $c */
       
   517         if ($c === 0) {
       
   518             // NOP, but we want a copy.
       
   519             $return->limbs = $this->limbs;
       
   520         } else {
       
   521             /** @var int $c */
       
   522 
       
   523             /** @var int $idx_shift */
       
   524             $idx_shift = ($c >> 4) & 1;
       
   525 
       
   526             /** @var int $sub_shift */
       
   527             $sub_shift = $c & 15;
       
   528 
       
   529             /** @var array<int, int> $limbs */
       
   530             $limbs =& $return->limbs;
       
   531 
       
   532             /** @var array<int, int> $myLimbs */
       
   533             $myLimbs =& $this->limbs;
       
   534 
       
   535             for ($i = 1; $i >= 0; --$i) {
       
   536                 /** @var int $j */
       
   537                 $j = ($i - $idx_shift) & 1;
       
   538                 /** @var int $k */
       
   539                 $k = ($i - $idx_shift - 1) & 1;
       
   540                 $limbs[$i] = (int) (
       
   541                     (
       
   542                         ((int) ($myLimbs[$j]) >> (int) ($sub_shift))
       
   543                             |
       
   544                         ((int) ($myLimbs[$k]) << (16 - (int) ($sub_shift)))
       
   545                     ) & 0xffff
       
   546                 );
       
   547             }
       
   548         }
       
   549         return $return;
       
   550     }
       
   551 
       
   552     /**
       
   553      * @param bool $bool
       
   554      * @return self
       
   555      */
       
   556     public function setUnsignedInt($bool = false)
       
   557     {
       
   558         $this->unsignedInt = !empty($bool);
       
   559         return $this;
       
   560     }
       
   561 
       
   562     /**
       
   563      * @param int $c
       
   564      * @return ParagonIE_Sodium_Core32_Int32
       
   565      * @throws SodiumException
       
   566      * @throws TypeError
       
   567      */
       
   568     public function shiftLeft($c = 0)
       
   569     {
       
   570         ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
       
   571         /** @var int $c */
       
   572         $c = (int) $c;
       
   573 
       
   574         $return = new ParagonIE_Sodium_Core32_Int32();
       
   575         $return->unsignedInt = $this->unsignedInt;
       
   576         $c &= 63;
       
   577         /** @var int $c */
       
   578         if ($c === 0) {
       
   579             $return->limbs = $this->limbs;
       
   580         } elseif ($c < 0) {
       
   581             /** @var int $c */
       
   582             return $this->shiftRight(-$c);
       
   583         } else {
       
   584             /** @var int $c */
       
   585             /** @var int $tmp */
       
   586             $tmp = $this->limbs[1] << $c;
       
   587             $return->limbs[1] = (int)($tmp & 0xffff);
       
   588             /** @var int $carry */
       
   589             $carry = $tmp >> 16;
       
   590 
       
   591             /** @var int $tmp */
       
   592             $tmp = ($this->limbs[0] << $c) | ($carry & 0xffff);
       
   593             $return->limbs[0] = (int) ($tmp & 0xffff);
       
   594         }
       
   595         return $return;
       
   596     }
       
   597 
       
   598     /**
       
   599      * @param int $c
       
   600      * @return ParagonIE_Sodium_Core32_Int32
       
   601      * @throws SodiumException
       
   602      * @throws TypeError
       
   603      * @psalm-suppress MixedAssignment
       
   604      * @psalm-suppress MixedOperand
       
   605      */
       
   606     public function shiftRight($c = 0)
       
   607     {
       
   608         ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
       
   609         /** @var int $c */
       
   610         $c = (int) $c;
       
   611 
       
   612         $return = new ParagonIE_Sodium_Core32_Int32();
       
   613         $return->unsignedInt = $this->unsignedInt;
       
   614         $c &= 63;
       
   615         /** @var int $c */
       
   616         if ($c >= 16) {
       
   617             $return->limbs = array(
       
   618                 (int) ($this->overflow & 0xffff),
       
   619                 (int) ($this->limbs[0])
       
   620             );
       
   621             $return->overflow = $this->overflow >> 16;
       
   622             return $return->shiftRight($c & 15);
       
   623         }
       
   624         if ($c === 0) {
       
   625             $return->limbs = $this->limbs;
       
   626         } elseif ($c < 0) {
       
   627             /** @var int $c */
       
   628             return $this->shiftLeft(-$c);
       
   629         } else {
       
   630             if (!is_int($c)) {
       
   631                 throw new TypeError();
       
   632             }
       
   633             /** @var int $c */
       
   634             // $return->limbs[0] = (int) (($this->limbs[0] >> $c) & 0xffff);
       
   635             $carryLeft = (int) ($this->overflow & ((1 << ($c + 1)) - 1));
       
   636             $return->limbs[0] = (int) ((($this->limbs[0] >> $c) | ($carryLeft << (16 - $c))) & 0xffff);
       
   637             $carryRight = (int) ($this->limbs[0] & ((1 << ($c + 1)) - 1));
       
   638             $return->limbs[1] = (int) ((($this->limbs[1] >> $c) | ($carryRight << (16 - $c))) & 0xffff);
       
   639             $return->overflow >>= $c;
       
   640         }
       
   641         return $return;
       
   642     }
       
   643 
       
   644     /**
       
   645      * Subtract a normal integer from an int32 object.
       
   646      *
       
   647      * @param int $int
       
   648      * @return ParagonIE_Sodium_Core32_Int32
       
   649      * @throws SodiumException
       
   650      * @throws TypeError
       
   651      */
       
   652     public function subInt($int)
       
   653     {
       
   654         ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
       
   655         /** @var int $int */
       
   656         $int = (int) $int;
       
   657 
       
   658         $return = new ParagonIE_Sodium_Core32_Int32();
       
   659         $return->unsignedInt = $this->unsignedInt;
       
   660 
       
   661         /** @var int $tmp */
       
   662         $tmp = $this->limbs[1] - ($int & 0xffff);
       
   663         /** @var int $carry */
       
   664         $carry = $tmp >> 16;
       
   665         $return->limbs[1] = (int) ($tmp & 0xffff);
       
   666 
       
   667         /** @var int $tmp */
       
   668         $tmp = $this->limbs[0] - (($int >> 16) & 0xffff) + $carry;
       
   669         $return->limbs[0] = (int) ($tmp & 0xffff);
       
   670         return $return;
       
   671     }
       
   672 
       
   673     /**
       
   674      * Subtract two int32 objects from each other
       
   675      *
       
   676      * @param ParagonIE_Sodium_Core32_Int32 $b
       
   677      * @return ParagonIE_Sodium_Core32_Int32
       
   678      */
       
   679     public function subInt32(ParagonIE_Sodium_Core32_Int32 $b)
       
   680     {
       
   681         $return = new ParagonIE_Sodium_Core32_Int32();
       
   682         $return->unsignedInt = $this->unsignedInt;
       
   683 
       
   684         /** @var int $tmp */
       
   685         $tmp = $this->limbs[1] - ($b->limbs[1] & 0xffff);
       
   686         /** @var int $carry */
       
   687         $carry = $tmp >> 16;
       
   688         $return->limbs[1] = (int) ($tmp & 0xffff);
       
   689 
       
   690         /** @var int $tmp */
       
   691         $tmp = $this->limbs[0] - ($b->limbs[0] & 0xffff) + $carry;
       
   692         $return->limbs[0] = (int) ($tmp & 0xffff);
       
   693         return $return;
       
   694     }
       
   695 
       
   696     /**
       
   697      * XOR this 32-bit integer with another.
       
   698      *
       
   699      * @param ParagonIE_Sodium_Core32_Int32 $b
       
   700      * @return ParagonIE_Sodium_Core32_Int32
       
   701      */
       
   702     public function xorInt32(ParagonIE_Sodium_Core32_Int32 $b)
       
   703     {
       
   704         $return = new ParagonIE_Sodium_Core32_Int32();
       
   705         $return->unsignedInt = $this->unsignedInt;
       
   706         $return->limbs = array(
       
   707             (int) ($this->limbs[0] ^ $b->limbs[0]),
       
   708             (int) ($this->limbs[1] ^ $b->limbs[1])
       
   709         );
       
   710         return $return;
       
   711     }
       
   712 
       
   713     /**
       
   714      * @param int $signed
       
   715      * @return self
       
   716      * @throws SodiumException
       
   717      * @throws TypeError
       
   718      */
       
   719     public static function fromInt($signed)
       
   720     {
       
   721         ParagonIE_Sodium_Core32_Util::declareScalarType($signed, 'int', 1);;
       
   722         /** @var int $signed */
       
   723         $signed = (int) $signed;
       
   724 
       
   725         return new ParagonIE_Sodium_Core32_Int32(
       
   726             array(
       
   727                 (int) (($signed >> 16) & 0xffff),
       
   728                 (int) ($signed & 0xffff)
       
   729             )
       
   730         );
       
   731     }
       
   732 
       
   733     /**
       
   734      * @param string $string
       
   735      * @return self
       
   736      * @throws SodiumException
       
   737      * @throws TypeError
       
   738      */
       
   739     public static function fromString($string)
       
   740     {
       
   741         ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
       
   742         $string = (string) $string;
       
   743         if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
       
   744             throw new RangeException(
       
   745                 'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
       
   746             );
       
   747         }
       
   748         $return = new ParagonIE_Sodium_Core32_Int32();
       
   749 
       
   750         $return->limbs[0]  = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8);
       
   751         $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff);
       
   752         $return->limbs[1]  = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8);
       
   753         $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff);
       
   754         return $return;
       
   755     }
       
   756 
       
   757     /**
       
   758      * @param string $string
       
   759      * @return self
       
   760      * @throws SodiumException
       
   761      * @throws TypeError
       
   762      */
       
   763     public static function fromReverseString($string)
       
   764     {
       
   765         ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
       
   766         $string = (string) $string;
       
   767         if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
       
   768             throw new RangeException(
       
   769                 'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
       
   770             );
       
   771         }
       
   772         $return = new ParagonIE_Sodium_Core32_Int32();
       
   773 
       
   774         $return->limbs[0]  = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8);
       
   775         $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff);
       
   776         $return->limbs[1]  = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8);
       
   777         $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff);
       
   778         return $return;
       
   779     }
       
   780 
       
   781     /**
       
   782      * @return array<int, int>
       
   783      */
       
   784     public function toArray()
       
   785     {
       
   786         return array((int) ($this->limbs[0] << 16 | $this->limbs[1]));
       
   787     }
       
   788 
       
   789     /**
       
   790      * @return string
       
   791      * @throws TypeError
       
   792      */
       
   793     public function toString()
       
   794     {
       
   795         return
       
   796             ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff) .
       
   797             ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) .
       
   798             ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) .
       
   799             ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff);
       
   800     }
       
   801 
       
   802     /**
       
   803      * @return int
       
   804      */
       
   805     public function toInt()
       
   806     {
       
   807         return (int) (
       
   808             (($this->limbs[0] & 0xffff) << 16)
       
   809                 |
       
   810             ($this->limbs[1] & 0xffff)
       
   811         );
       
   812     }
       
   813 
       
   814     /**
       
   815      * @return ParagonIE_Sodium_Core32_Int32
       
   816      */
       
   817     public function toInt32()
       
   818     {
       
   819         $return = new ParagonIE_Sodium_Core32_Int32();
       
   820         $return->limbs[0] = (int) ($this->limbs[0] & 0xffff);
       
   821         $return->limbs[1] = (int) ($this->limbs[1] & 0xffff);
       
   822         $return->unsignedInt = $this->unsignedInt;
       
   823         $return->overflow = (int) ($this->overflow & 0x7fffffff);
       
   824         return $return;
       
   825     }
       
   826 
       
   827     /**
       
   828      * @return ParagonIE_Sodium_Core32_Int64
       
   829      */
       
   830     public function toInt64()
       
   831     {
       
   832         $return = new ParagonIE_Sodium_Core32_Int64();
       
   833         $return->unsignedInt = $this->unsignedInt;
       
   834         if ($this->unsignedInt) {
       
   835             $return->limbs[0] += (($this->overflow >> 16) & 0xffff);
       
   836             $return->limbs[1] += (($this->overflow) & 0xffff);
       
   837         } else {
       
   838             $neg = -(($this->limbs[0] >> 15) & 1);
       
   839             $return->limbs[0] = (int)($neg & 0xffff);
       
   840             $return->limbs[1] = (int)($neg & 0xffff);
       
   841         }
       
   842         $return->limbs[2] = (int) ($this->limbs[0] & 0xffff);
       
   843         $return->limbs[3] = (int) ($this->limbs[1] & 0xffff);
       
   844         return $return;
       
   845     }
       
   846 
       
   847     /**
       
   848      * @return string
       
   849      * @throws TypeError
       
   850      */
       
   851     public function toReverseString()
       
   852     {
       
   853         return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) .
       
   854             ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) .
       
   855             ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) .
       
   856             ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff);
       
   857     }
       
   858 
       
   859     /**
       
   860      * @return string
       
   861      */
       
   862     public function __toString()
       
   863     {
       
   864         try {
       
   865             return $this->toString();
       
   866         } catch (TypeError $ex) {
       
   867             // PHP engine can't handle exceptions from __toString()
       
   868             return '';
       
   869         }
       
   870     }
       
   871 }