balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

Int32.php (24542B)


      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 }