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