angelovcom.net

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

Curve25519.php (134754B)


      1 <?php
      2 
      3 if (class_exists('ParagonIE_Sodium_Core32_Curve25519', false)) {
      4     return;
      5 }
      6 
      7 /**
      8  * Class ParagonIE_Sodium_Core32_Curve25519
      9  *
     10  * Implements Curve25519 core functions
     11  *
     12  * Based on the ref10 curve25519 code provided by libsodium
     13  *
     14  * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
     15  */
     16 abstract class ParagonIE_Sodium_Core32_Curve25519 extends ParagonIE_Sodium_Core32_Curve25519_H
     17 {
     18     /**
     19      * Get a field element of size 10 with a value of 0
     20      *
     21      * @internal You should not use this directly from another application
     22      *
     23      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
     24      * @throws SodiumException
     25      * @throws TypeError
     26      */
     27     public static function fe_0()
     28     {
     29         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
     30             array(
     31                 new ParagonIE_Sodium_Core32_Int32(),
     32                 new ParagonIE_Sodium_Core32_Int32(),
     33                 new ParagonIE_Sodium_Core32_Int32(),
     34                 new ParagonIE_Sodium_Core32_Int32(),
     35                 new ParagonIE_Sodium_Core32_Int32(),
     36                 new ParagonIE_Sodium_Core32_Int32(),
     37                 new ParagonIE_Sodium_Core32_Int32(),
     38                 new ParagonIE_Sodium_Core32_Int32(),
     39                 new ParagonIE_Sodium_Core32_Int32(),
     40                 new ParagonIE_Sodium_Core32_Int32()
     41             )
     42         );
     43     }
     44 
     45     /**
     46      * Get a field element of size 10 with a value of 1
     47      *
     48      * @internal You should not use this directly from another application
     49      *
     50      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
     51      * @throws SodiumException
     52      * @throws TypeError
     53      */
     54     public static function fe_1()
     55     {
     56         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
     57             array(
     58                 ParagonIE_Sodium_Core32_Int32::fromInt(1),
     59                 new ParagonIE_Sodium_Core32_Int32(),
     60                 new ParagonIE_Sodium_Core32_Int32(),
     61                 new ParagonIE_Sodium_Core32_Int32(),
     62                 new ParagonIE_Sodium_Core32_Int32(),
     63                 new ParagonIE_Sodium_Core32_Int32(),
     64                 new ParagonIE_Sodium_Core32_Int32(),
     65                 new ParagonIE_Sodium_Core32_Int32(),
     66                 new ParagonIE_Sodium_Core32_Int32(),
     67                 new ParagonIE_Sodium_Core32_Int32()
     68             )
     69         );
     70     }
     71 
     72     /**
     73      * Add two field elements.
     74      *
     75      * @internal You should not use this directly from another application
     76      *
     77      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
     78      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
     79      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
     80      * @throws SodiumException
     81      * @throws TypeError
     82      * @psalm-suppress MixedAssignment
     83      * @psalm-suppress MixedMethodCall
     84      */
     85     public static function fe_add(
     86         ParagonIE_Sodium_Core32_Curve25519_Fe $f,
     87         ParagonIE_Sodium_Core32_Curve25519_Fe $g
     88     ) {
     89         $arr = array();
     90         for ($i = 0; $i < 10; ++$i) {
     91             $arr[$i] = $f[$i]->addInt32($g[$i]);
     92         }
     93         /** @var array<int, ParagonIE_Sodium_Core32_Int32> $arr */
     94         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($arr);
     95     }
     96 
     97     /**
     98      * Constant-time conditional move.
     99      *
    100      * @internal You should not use this directly from another application
    101      *
    102      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    103      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
    104      * @param int $b
    105      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    106      * @throws SodiumException
    107      * @throws TypeError
    108      * @psalm-suppress MixedAssignment
    109      * @psalm-suppress MixedMethodCall
    110      */
    111     public static function fe_cmov(
    112         ParagonIE_Sodium_Core32_Curve25519_Fe $f,
    113         ParagonIE_Sodium_Core32_Curve25519_Fe $g,
    114         $b = 0
    115     ) {
    116         /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
    117         $h = array();
    118         for ($i = 0; $i < 10; ++$i) {
    119             if (!($f[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
    120                 throw new TypeError('Expected Int32');
    121             }
    122             if (!($g[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
    123                 throw new TypeError('Expected Int32');
    124             }
    125             $h[$i] = $f[$i]->xorInt32(
    126                 $f[$i]->xorInt32($g[$i])->mask($b)
    127             );
    128         }
    129         /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
    130         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h);
    131     }
    132 
    133     /**
    134      * Create a copy of a field element.
    135      *
    136      * @internal You should not use this directly from another application
    137      *
    138      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    139      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    140      */
    141     public static function fe_copy(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
    142     {
    143         $h = clone $f;
    144         return $h;
    145     }
    146 
    147     /**
    148      * Give: 32-byte string.
    149      * Receive: A field element object to use for internal calculations.
    150      *
    151      * @internal You should not use this directly from another application
    152      *
    153      * @param string $s
    154      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    155      * @throws RangeException
    156      * @throws SodiumException
    157      * @throws TypeError
    158      * @psalm-suppress MixedMethodCall
    159      */
    160     public static function fe_frombytes($s)
    161     {
    162         if (self::strlen($s) !== 32) {
    163             throw new RangeException('Expected a 32-byte string.');
    164         }
    165         /** @var ParagonIE_Sodium_Core32_Int32 $h0 */
    166         $h0 = ParagonIE_Sodium_Core32_Int32::fromInt(
    167             self::load_4($s)
    168         );
    169         /** @var ParagonIE_Sodium_Core32_Int32 $h1 */
    170         $h1 = ParagonIE_Sodium_Core32_Int32::fromInt(
    171             self::load_3(self::substr($s, 4, 3)) << 6
    172         );
    173         /** @var ParagonIE_Sodium_Core32_Int32 $h2 */
    174         $h2 = ParagonIE_Sodium_Core32_Int32::fromInt(
    175             self::load_3(self::substr($s, 7, 3)) << 5
    176         );
    177         /** @var ParagonIE_Sodium_Core32_Int32 $h3 */
    178         $h3 = ParagonIE_Sodium_Core32_Int32::fromInt(
    179             self::load_3(self::substr($s, 10, 3)) << 3
    180         );
    181         /** @var ParagonIE_Sodium_Core32_Int32 $h4 */
    182         $h4 = ParagonIE_Sodium_Core32_Int32::fromInt(
    183             self::load_3(self::substr($s, 13, 3)) << 2
    184         );
    185         /** @var ParagonIE_Sodium_Core32_Int32 $h5 */
    186         $h5 = ParagonIE_Sodium_Core32_Int32::fromInt(
    187             self::load_4(self::substr($s, 16, 4))
    188         );
    189         /** @var ParagonIE_Sodium_Core32_Int32 $h6 */
    190         $h6 = ParagonIE_Sodium_Core32_Int32::fromInt(
    191             self::load_3(self::substr($s, 20, 3)) << 7
    192         );
    193         /** @var ParagonIE_Sodium_Core32_Int32 $h7 */
    194         $h7 = ParagonIE_Sodium_Core32_Int32::fromInt(
    195             self::load_3(self::substr($s, 23, 3)) << 5
    196         );
    197         /** @var ParagonIE_Sodium_Core32_Int32 $h8 */
    198         $h8 = ParagonIE_Sodium_Core32_Int32::fromInt(
    199             self::load_3(self::substr($s, 26, 3)) << 4
    200         );
    201         /** @var ParagonIE_Sodium_Core32_Int32 $h9 */
    202         $h9 = ParagonIE_Sodium_Core32_Int32::fromInt(
    203             (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2
    204         );
    205 
    206         $carry9 = $h9->addInt(1 << 24)->shiftRight(25);
    207         $h0 = $h0->addInt32($carry9->mulInt(19, 5));
    208         $h9 = $h9->subInt32($carry9->shiftLeft(25));
    209 
    210         $carry1 = $h1->addInt(1 << 24)->shiftRight(25);
    211         $h2 = $h2->addInt32($carry1);
    212         $h1 = $h1->subInt32($carry1->shiftLeft(25));
    213 
    214         $carry3 = $h3->addInt(1 << 24)->shiftRight(25);
    215         $h4 = $h4->addInt32($carry3);
    216         $h3 = $h3->subInt32($carry3->shiftLeft(25));
    217 
    218         $carry5 = $h5->addInt(1 << 24)->shiftRight(25);
    219         $h6 = $h6->addInt32($carry5);
    220         $h5 = $h5->subInt32($carry5->shiftLeft(25));
    221 
    222         $carry7 = $h7->addInt(1 << 24)->shiftRight(25);
    223         $h8 = $h8->addInt32($carry7);
    224         $h7 = $h7->subInt32($carry7->shiftLeft(25));
    225 
    226         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
    227         $h1 = $h1->addInt32($carry0);
    228         $h0 = $h0->subInt32($carry0->shiftLeft(26));
    229 
    230         $carry2 = $h2->addInt(1 << 25)->shiftRight(26);
    231         $h3 = $h3->addInt32($carry2);
    232         $h2 = $h2->subInt32($carry2->shiftLeft(26));
    233 
    234         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
    235         $h5 = $h5->addInt32($carry4);
    236         $h4 = $h4->subInt32($carry4->shiftLeft(26));
    237 
    238         $carry6 = $h6->addInt(1 << 25)->shiftRight(26);
    239         $h7 = $h7->addInt32($carry6);
    240         $h6 = $h6->subInt32($carry6->shiftLeft(26));
    241 
    242         $carry8 = $h8->addInt(1 << 25)->shiftRight(26);
    243         $h9 = $h9->addInt32($carry8);
    244         $h8 = $h8->subInt32($carry8->shiftLeft(26));
    245 
    246         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
    247             array($h0, $h1, $h2,$h3, $h4, $h5, $h6, $h7, $h8, $h9)
    248         );
    249     }
    250 
    251     /**
    252      * Convert a field element to a byte string.
    253      *
    254      * @internal You should not use this directly from another application
    255      *
    256      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $h
    257      * @return string
    258      * @throws SodiumException
    259      * @throws TypeError
    260      * @psalm-suppress MixedAssignment
    261      * @psalm-suppress MixedMethodCall
    262      */
    263     public static function fe_tobytes(ParagonIE_Sodium_Core32_Curve25519_Fe $h)
    264     {
    265         /**
    266          * @var ParagonIE_Sodium_Core32_Int64[] $f
    267          * @var ParagonIE_Sodium_Core32_Int64 $q
    268          */
    269         $f = array();
    270 
    271         for ($i = 0; $i < 10; ++$i) {
    272             $f[$i] = $h[$i]->toInt64();
    273         }
    274 
    275         $q = $f[9]->mulInt(19, 5)->addInt(1 << 14)->shiftRight(25)
    276             ->addInt64($f[0])->shiftRight(26)
    277             ->addInt64($f[1])->shiftRight(25)
    278             ->addInt64($f[2])->shiftRight(26)
    279             ->addInt64($f[3])->shiftRight(25)
    280             ->addInt64($f[4])->shiftRight(26)
    281             ->addInt64($f[5])->shiftRight(25)
    282             ->addInt64($f[6])->shiftRight(26)
    283             ->addInt64($f[7])->shiftRight(25)
    284             ->addInt64($f[8])->shiftRight(26)
    285             ->addInt64($f[9])->shiftRight(25);
    286 
    287         $f[0] = $f[0]->addInt64($q->mulInt(19, 5));
    288 
    289         $carry0 = $f[0]->shiftRight(26);
    290         $f[1] = $f[1]->addInt64($carry0);
    291         $f[0] = $f[0]->subInt64($carry0->shiftLeft(26));
    292 
    293         $carry1 = $f[1]->shiftRight(25);
    294         $f[2] = $f[2]->addInt64($carry1);
    295         $f[1] = $f[1]->subInt64($carry1->shiftLeft(25));
    296 
    297         $carry2 = $f[2]->shiftRight(26);
    298         $f[3] = $f[3]->addInt64($carry2);
    299         $f[2] = $f[2]->subInt64($carry2->shiftLeft(26));
    300 
    301         $carry3 = $f[3]->shiftRight(25);
    302         $f[4] = $f[4]->addInt64($carry3);
    303         $f[3] = $f[3]->subInt64($carry3->shiftLeft(25));
    304 
    305         $carry4 = $f[4]->shiftRight(26);
    306         $f[5] = $f[5]->addInt64($carry4);
    307         $f[4] = $f[4]->subInt64($carry4->shiftLeft(26));
    308 
    309         $carry5 = $f[5]->shiftRight(25);
    310         $f[6] = $f[6]->addInt64($carry5);
    311         $f[5] = $f[5]->subInt64($carry5->shiftLeft(25));
    312 
    313         $carry6 = $f[6]->shiftRight(26);
    314         $f[7] = $f[7]->addInt64($carry6);
    315         $f[6] = $f[6]->subInt64($carry6->shiftLeft(26));
    316 
    317         $carry7 = $f[7]->shiftRight(25);
    318         $f[8] = $f[8]->addInt64($carry7);
    319         $f[7] = $f[7]->subInt64($carry7->shiftLeft(25));
    320 
    321         $carry8 = $f[8]->shiftRight(26);
    322         $f[9] = $f[9]->addInt64($carry8);
    323         $f[8] = $f[8]->subInt64($carry8->shiftLeft(26));
    324 
    325         $carry9 = $f[9]->shiftRight(25);
    326         $f[9] = $f[9]->subInt64($carry9->shiftLeft(25));
    327 
    328         /** @var int $h0 */
    329         $h0 = $f[0]->toInt32()->toInt();
    330         /** @var int $h1 */
    331         $h1 = $f[1]->toInt32()->toInt();
    332         /** @var int $h2 */
    333         $h2 = $f[2]->toInt32()->toInt();
    334         /** @var int $h3 */
    335         $h3 = $f[3]->toInt32()->toInt();
    336         /** @var int $h4 */
    337         $h4 = $f[4]->toInt32()->toInt();
    338         /** @var int $h5 */
    339         $h5 = $f[5]->toInt32()->toInt();
    340         /** @var int $h6 */
    341         $h6 = $f[6]->toInt32()->toInt();
    342         /** @var int $h7 */
    343         $h7 = $f[7]->toInt32()->toInt();
    344         /** @var int $h8 */
    345         $h8 = $f[8]->toInt32()->toInt();
    346         /** @var int $h9 */
    347         $h9 = $f[9]->toInt32()->toInt();
    348 
    349         /**
    350          * @var array<int, int>
    351          */
    352         $s = array(
    353             (int) (($h0 >> 0) & 0xff),
    354             (int) (($h0 >> 8) & 0xff),
    355             (int) (($h0 >> 16) & 0xff),
    356             (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
    357             (int) (($h1 >> 6) & 0xff),
    358             (int) (($h1 >> 14) & 0xff),
    359             (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
    360             (int) (($h2 >> 5) & 0xff),
    361             (int) (($h2 >> 13) & 0xff),
    362             (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
    363             (int) (($h3 >> 3) & 0xff),
    364             (int) (($h3 >> 11) & 0xff),
    365             (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
    366             (int) (($h4 >> 2) & 0xff),
    367             (int) (($h4 >> 10) & 0xff),
    368             (int) (($h4 >> 18) & 0xff),
    369             (int) (($h5 >> 0) & 0xff),
    370             (int) (($h5 >> 8) & 0xff),
    371             (int) (($h5 >> 16) & 0xff),
    372             (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
    373             (int) (($h6 >> 7) & 0xff),
    374             (int) (($h6 >> 15) & 0xff),
    375             (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
    376             (int) (($h7 >> 5) & 0xff),
    377             (int) (($h7 >> 13) & 0xff),
    378             (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
    379             (int) (($h8 >> 4) & 0xff),
    380             (int) (($h8 >> 12) & 0xff),
    381             (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
    382             (int) (($h9 >> 2) & 0xff),
    383             (int) (($h9 >> 10) & 0xff),
    384             (int) (($h9 >> 18) & 0xff)
    385         );
    386         return self::intArrayToString($s);
    387     }
    388 
    389     /**
    390      * Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
    391      *
    392      * @internal You should not use this directly from another application
    393      *
    394      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    395      * @return int
    396      * @throws SodiumException
    397      * @throws TypeError
    398      */
    399     public static function fe_isnegative(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
    400     {
    401         $str = self::fe_tobytes($f);
    402         return (int) (self::chrToInt($str[0]) & 1);
    403     }
    404 
    405     /**
    406      * Returns 0 if this field element results in all NUL bytes.
    407      *
    408      * @internal You should not use this directly from another application
    409      *
    410      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    411      * @return bool
    412      * @throws SodiumException
    413      * @throws TypeError
    414      */
    415     public static function fe_isnonzero(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
    416     {
    417         static $zero;
    418         if ($zero === null) {
    419             $zero = str_repeat("\x00", 32);
    420         }
    421         /** @var string $str */
    422         $str = self::fe_tobytes($f);
    423         /** @var string $zero */
    424         return !self::verify_32($str, $zero);
    425     }
    426 
    427     /**
    428      * Multiply two field elements
    429      *
    430      * h = f * g
    431      *
    432      * @internal You should not use this directly from another application
    433      *
    434      * @security Is multiplication a source of timing leaks? If so, can we do
    435      *           anything to prevent that from happening?
    436      *
    437      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    438      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
    439      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    440      * @throws SodiumException
    441      * @throws TypeError
    442      */
    443     public static function fe_mul(
    444         ParagonIE_Sodium_Core32_Curve25519_Fe $f,
    445         ParagonIE_Sodium_Core32_Curve25519_Fe $g
    446     ) {
    447         /**
    448          * @var ParagonIE_Sodium_Core32_Int32[] $f
    449          * @var ParagonIE_Sodium_Core32_Int32[] $g
    450          * @var ParagonIE_Sodium_Core32_Int64 $f0
    451          * @var ParagonIE_Sodium_Core32_Int64 $f1
    452          * @var ParagonIE_Sodium_Core32_Int64 $f2
    453          * @var ParagonIE_Sodium_Core32_Int64 $f3
    454          * @var ParagonIE_Sodium_Core32_Int64 $f4
    455          * @var ParagonIE_Sodium_Core32_Int64 $f5
    456          * @var ParagonIE_Sodium_Core32_Int64 $f6
    457          * @var ParagonIE_Sodium_Core32_Int64 $f7
    458          * @var ParagonIE_Sodium_Core32_Int64 $f8
    459          * @var ParagonIE_Sodium_Core32_Int64 $f9
    460          * @var ParagonIE_Sodium_Core32_Int64 $g0
    461          * @var ParagonIE_Sodium_Core32_Int64 $g1
    462          * @var ParagonIE_Sodium_Core32_Int64 $g2
    463          * @var ParagonIE_Sodium_Core32_Int64 $g3
    464          * @var ParagonIE_Sodium_Core32_Int64 $g4
    465          * @var ParagonIE_Sodium_Core32_Int64 $g5
    466          * @var ParagonIE_Sodium_Core32_Int64 $g6
    467          * @var ParagonIE_Sodium_Core32_Int64 $g7
    468          * @var ParagonIE_Sodium_Core32_Int64 $g8
    469          * @var ParagonIE_Sodium_Core32_Int64 $g9
    470          */
    471         $f0 = $f[0]->toInt64();
    472         $f1 = $f[1]->toInt64();
    473         $f2 = $f[2]->toInt64();
    474         $f3 = $f[3]->toInt64();
    475         $f4 = $f[4]->toInt64();
    476         $f5 = $f[5]->toInt64();
    477         $f6 = $f[6]->toInt64();
    478         $f7 = $f[7]->toInt64();
    479         $f8 = $f[8]->toInt64();
    480         $f9 = $f[9]->toInt64();
    481         $g0 = $g[0]->toInt64();
    482         $g1 = $g[1]->toInt64();
    483         $g2 = $g[2]->toInt64();
    484         $g3 = $g[3]->toInt64();
    485         $g4 = $g[4]->toInt64();
    486         $g5 = $g[5]->toInt64();
    487         $g6 = $g[6]->toInt64();
    488         $g7 = $g[7]->toInt64();
    489         $g8 = $g[8]->toInt64();
    490         $g9 = $g[9]->toInt64();
    491         $g1_19 = $g1->mulInt(19, 5); /* 2^4 <= 19 <= 2^5, but we only want 5 bits */
    492         $g2_19 = $g2->mulInt(19, 5);
    493         $g3_19 = $g3->mulInt(19, 5);
    494         $g4_19 = $g4->mulInt(19, 5);
    495         $g5_19 = $g5->mulInt(19, 5);
    496         $g6_19 = $g6->mulInt(19, 5);
    497         $g7_19 = $g7->mulInt(19, 5);
    498         $g8_19 = $g8->mulInt(19, 5);
    499         $g9_19 = $g9->mulInt(19, 5);
    500         /** @var ParagonIE_Sodium_Core32_Int64 $f1_2 */
    501         $f1_2 = $f1->shiftLeft(1);
    502         /** @var ParagonIE_Sodium_Core32_Int64 $f3_2 */
    503         $f3_2 = $f3->shiftLeft(1);
    504         /** @var ParagonIE_Sodium_Core32_Int64 $f5_2 */
    505         $f5_2 = $f5->shiftLeft(1);
    506         /** @var ParagonIE_Sodium_Core32_Int64 $f7_2 */
    507         $f7_2 = $f7->shiftLeft(1);
    508         /** @var ParagonIE_Sodium_Core32_Int64 $f9_2 */
    509         $f9_2 = $f9->shiftLeft(1);
    510         $f0g0    = $f0->mulInt64($g0, 27);
    511         $f0g1    = $f0->mulInt64($g1, 27);
    512         $f0g2    = $f0->mulInt64($g2, 27);
    513         $f0g3    = $f0->mulInt64($g3, 27);
    514         $f0g4    = $f0->mulInt64($g4, 27);
    515         $f0g5    = $f0->mulInt64($g5, 27);
    516         $f0g6    = $f0->mulInt64($g6, 27);
    517         $f0g7    = $f0->mulInt64($g7, 27);
    518         $f0g8    = $f0->mulInt64($g8, 27);
    519         $f0g9    = $f0->mulInt64($g9, 27);
    520         $f1g0    = $f1->mulInt64($g0, 27);
    521         $f1g1_2  = $f1_2->mulInt64($g1, 27);
    522         $f1g2    = $f1->mulInt64($g2, 27);
    523         $f1g3_2  = $f1_2->mulInt64($g3, 27);
    524         $f1g4    = $f1->mulInt64($g4, 30);
    525         $f1g5_2  = $f1_2->mulInt64($g5, 30);
    526         $f1g6    = $f1->mulInt64($g6, 30);
    527         $f1g7_2  = $f1_2->mulInt64($g7, 30);
    528         $f1g8    = $f1->mulInt64($g8, 30);
    529         $f1g9_38 = $g9_19->mulInt64($f1_2, 30);
    530         $f2g0    = $f2->mulInt64($g0, 30);
    531         $f2g1    = $f2->mulInt64($g1, 29);
    532         $f2g2    = $f2->mulInt64($g2, 30);
    533         $f2g3    = $f2->mulInt64($g3, 29);
    534         $f2g4    = $f2->mulInt64($g4, 30);
    535         $f2g5    = $f2->mulInt64($g5, 29);
    536         $f2g6    = $f2->mulInt64($g6, 30);
    537         $f2g7    = $f2->mulInt64($g7, 29);
    538         $f2g8_19 = $g8_19->mulInt64($f2, 30);
    539         $f2g9_19 = $g9_19->mulInt64($f2, 30);
    540         $f3g0    = $f3->mulInt64($g0, 30);
    541         $f3g1_2  = $f3_2->mulInt64($g1, 30);
    542         $f3g2    = $f3->mulInt64($g2, 30);
    543         $f3g3_2  = $f3_2->mulInt64($g3, 30);
    544         $f3g4    = $f3->mulInt64($g4, 30);
    545         $f3g5_2  = $f3_2->mulInt64($g5, 30);
    546         $f3g6    = $f3->mulInt64($g6, 30);
    547         $f3g7_38 = $g7_19->mulInt64($f3_2, 30);
    548         $f3g8_19 = $g8_19->mulInt64($f3, 30);
    549         $f3g9_38 = $g9_19->mulInt64($f3_2, 30);
    550         $f4g0    = $f4->mulInt64($g0, 30);
    551         $f4g1    = $f4->mulInt64($g1, 30);
    552         $f4g2    = $f4->mulInt64($g2, 30);
    553         $f4g3    = $f4->mulInt64($g3, 30);
    554         $f4g4    = $f4->mulInt64($g4, 30);
    555         $f4g5    = $f4->mulInt64($g5, 30);
    556         $f4g6_19 = $g6_19->mulInt64($f4, 30);
    557         $f4g7_19 = $g7_19->mulInt64($f4, 30);
    558         $f4g8_19 = $g8_19->mulInt64($f4, 30);
    559         $f4g9_19 = $g9_19->mulInt64($f4, 30);
    560         $f5g0    = $f5->mulInt64($g0, 30);
    561         $f5g1_2  = $f5_2->mulInt64($g1, 30);
    562         $f5g2    = $f5->mulInt64($g2, 30);
    563         $f5g3_2  = $f5_2->mulInt64($g3, 30);
    564         $f5g4    = $f5->mulInt64($g4, 30);
    565         $f5g5_38 = $g5_19->mulInt64($f5_2, 30);
    566         $f5g6_19 = $g6_19->mulInt64($f5, 30);
    567         $f5g7_38 = $g7_19->mulInt64($f5_2, 30);
    568         $f5g8_19 = $g8_19->mulInt64($f5, 30);
    569         $f5g9_38 = $g9_19->mulInt64($f5_2, 30);
    570         $f6g0    = $f6->mulInt64($g0, 30);
    571         $f6g1    = $f6->mulInt64($g1, 30);
    572         $f6g2    = $f6->mulInt64($g2, 30);
    573         $f6g3    = $f6->mulInt64($g3, 30);
    574         $f6g4_19 = $g4_19->mulInt64($f6, 30);
    575         $f6g5_19 = $g5_19->mulInt64($f6, 30);
    576         $f6g6_19 = $g6_19->mulInt64($f6, 30);
    577         $f6g7_19 = $g7_19->mulInt64($f6, 30);
    578         $f6g8_19 = $g8_19->mulInt64($f6, 30);
    579         $f6g9_19 = $g9_19->mulInt64($f6, 30);
    580         $f7g0    = $f7->mulInt64($g0, 30);
    581         $f7g1_2  = $g1->mulInt64($f7_2, 30);
    582         $f7g2    = $f7->mulInt64($g2, 30);
    583         $f7g3_38 = $g3_19->mulInt64($f7_2, 30);
    584         $f7g4_19 = $g4_19->mulInt64($f7, 30);
    585         $f7g5_38 = $g5_19->mulInt64($f7_2, 30);
    586         $f7g6_19 = $g6_19->mulInt64($f7, 30);
    587         $f7g7_38 = $g7_19->mulInt64($f7_2, 30);
    588         $f7g8_19 = $g8_19->mulInt64($f7, 30);
    589         $f7g9_38 = $g9_19->mulInt64($f7_2, 30);
    590         $f8g0    = $f8->mulInt64($g0, 30);
    591         $f8g1    = $f8->mulInt64($g1, 29);
    592         $f8g2_19 = $g2_19->mulInt64($f8, 30);
    593         $f8g3_19 = $g3_19->mulInt64($f8, 30);
    594         $f8g4_19 = $g4_19->mulInt64($f8, 30);
    595         $f8g5_19 = $g5_19->mulInt64($f8, 30);
    596         $f8g6_19 = $g6_19->mulInt64($f8, 30);
    597         $f8g7_19 = $g7_19->mulInt64($f8, 30);
    598         $f8g8_19 = $g8_19->mulInt64($f8, 30);
    599         $f8g9_19 = $g9_19->mulInt64($f8, 30);
    600         $f9g0    = $f9->mulInt64($g0, 30);
    601         $f9g1_38 = $g1_19->mulInt64($f9_2, 30);
    602         $f9g2_19 = $g2_19->mulInt64($f9, 30);
    603         $f9g3_38 = $g3_19->mulInt64($f9_2, 30);
    604         $f9g4_19 = $g4_19->mulInt64($f9, 30);
    605         $f9g5_38 = $g5_19->mulInt64($f9_2, 30);
    606         $f9g6_19 = $g6_19->mulInt64($f9, 30);
    607         $f9g7_38 = $g7_19->mulInt64($f9_2, 30);
    608         $f9g8_19 = $g8_19->mulInt64($f9, 30);
    609         $f9g9_38 = $g9_19->mulInt64($f9_2, 30);
    610 
    611         // $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
    612         $h0 = $f0g0->addInt64($f1g9_38)->addInt64($f2g8_19)->addInt64($f3g7_38)
    613             ->addInt64($f4g6_19)->addInt64($f5g5_38)->addInt64($f6g4_19)
    614             ->addInt64($f7g3_38)->addInt64($f8g2_19)->addInt64($f9g1_38);
    615 
    616         // $h1 = $f0g1 + $f1g0    + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
    617         $h1 = $f0g1->addInt64($f1g0)->addInt64($f2g9_19)->addInt64($f3g8_19)
    618             ->addInt64($f4g7_19)->addInt64($f5g6_19)->addInt64($f6g5_19)
    619             ->addInt64($f7g4_19)->addInt64($f8g3_19)->addInt64($f9g2_19);
    620 
    621         // $h2 = $f0g2 + $f1g1_2  + $f2g0    + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
    622         $h2 = $f0g2->addInt64($f1g1_2)->addInt64($f2g0)->addInt64($f3g9_38)
    623             ->addInt64($f4g8_19)->addInt64($f5g7_38)->addInt64($f6g6_19)
    624             ->addInt64($f7g5_38)->addInt64($f8g4_19)->addInt64($f9g3_38);
    625 
    626         // $h3 = $f0g3 + $f1g2    + $f2g1    + $f3g0    + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
    627         $h3 = $f0g3->addInt64($f1g2)->addInt64($f2g1)->addInt64($f3g0)
    628             ->addInt64($f4g9_19)->addInt64($f5g8_19)->addInt64($f6g7_19)
    629             ->addInt64($f7g6_19)->addInt64($f8g5_19)->addInt64($f9g4_19);
    630 
    631         // $h4 = $f0g4 + $f1g3_2  + $f2g2    + $f3g1_2  + $f4g0    + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
    632         $h4 = $f0g4->addInt64($f1g3_2)->addInt64($f2g2)->addInt64($f3g1_2)
    633             ->addInt64($f4g0)->addInt64($f5g9_38)->addInt64($f6g8_19)
    634             ->addInt64($f7g7_38)->addInt64($f8g6_19)->addInt64($f9g5_38);
    635 
    636         // $h5 = $f0g5 + $f1g4    + $f2g3    + $f3g2    + $f4g1    + $f5g0    + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
    637         $h5 = $f0g5->addInt64($f1g4)->addInt64($f2g3)->addInt64($f3g2)
    638             ->addInt64($f4g1)->addInt64($f5g0)->addInt64($f6g9_19)
    639             ->addInt64($f7g8_19)->addInt64($f8g7_19)->addInt64($f9g6_19);
    640 
    641         // $h6 = $f0g6 + $f1g5_2  + $f2g4    + $f3g3_2  + $f4g2    + $f5g1_2  + $f6g0    + $f7g9_38 + $f8g8_19 + $f9g7_38;
    642         $h6 = $f0g6->addInt64($f1g5_2)->addInt64($f2g4)->addInt64($f3g3_2)
    643             ->addInt64($f4g2)->addInt64($f5g1_2)->addInt64($f6g0)
    644             ->addInt64($f7g9_38)->addInt64($f8g8_19)->addInt64($f9g7_38);
    645 
    646         // $h7 = $f0g7 + $f1g6    + $f2g5    + $f3g4    + $f4g3    + $f5g2    + $f6g1    + $f7g0    + $f8g9_19 + $f9g8_19;
    647         $h7 = $f0g7->addInt64($f1g6)->addInt64($f2g5)->addInt64($f3g4)
    648             ->addInt64($f4g3)->addInt64($f5g2)->addInt64($f6g1)
    649             ->addInt64($f7g0)->addInt64($f8g9_19)->addInt64($f9g8_19);
    650 
    651         // $h8 = $f0g8 + $f1g7_2  + $f2g6    + $f3g5_2  + $f4g4    + $f5g3_2  + $f6g2    + $f7g1_2  + $f8g0    + $f9g9_38;
    652         $h8 = $f0g8->addInt64($f1g7_2)->addInt64($f2g6)->addInt64($f3g5_2)
    653             ->addInt64($f4g4)->addInt64($f5g3_2)->addInt64($f6g2)
    654             ->addInt64($f7g1_2)->addInt64($f8g0)->addInt64($f9g9_38);
    655 
    656         // $h9 = $f0g9 + $f1g8    + $f2g7    + $f3g6    + $f4g5    + $f5g4    + $f6g3    + $f7g2    + $f8g1    + $f9g0   ;
    657         $h9 = $f0g9->addInt64($f1g8)->addInt64($f2g7)->addInt64($f3g6)
    658             ->addInt64($f4g5)->addInt64($f5g4)->addInt64($f6g3)
    659             ->addInt64($f7g2)->addInt64($f8g1)->addInt64($f9g0);
    660 
    661         /**
    662          * @var ParagonIE_Sodium_Core32_Int64 $h0
    663          * @var ParagonIE_Sodium_Core32_Int64 $h1
    664          * @var ParagonIE_Sodium_Core32_Int64 $h2
    665          * @var ParagonIE_Sodium_Core32_Int64 $h3
    666          * @var ParagonIE_Sodium_Core32_Int64 $h4
    667          * @var ParagonIE_Sodium_Core32_Int64 $h5
    668          * @var ParagonIE_Sodium_Core32_Int64 $h6
    669          * @var ParagonIE_Sodium_Core32_Int64 $h7
    670          * @var ParagonIE_Sodium_Core32_Int64 $h8
    671          * @var ParagonIE_Sodium_Core32_Int64 $h9
    672          * @var ParagonIE_Sodium_Core32_Int64 $carry0
    673          * @var ParagonIE_Sodium_Core32_Int64 $carry1
    674          * @var ParagonIE_Sodium_Core32_Int64 $carry2
    675          * @var ParagonIE_Sodium_Core32_Int64 $carry3
    676          * @var ParagonIE_Sodium_Core32_Int64 $carry4
    677          * @var ParagonIE_Sodium_Core32_Int64 $carry5
    678          * @var ParagonIE_Sodium_Core32_Int64 $carry6
    679          * @var ParagonIE_Sodium_Core32_Int64 $carry7
    680          * @var ParagonIE_Sodium_Core32_Int64 $carry8
    681          * @var ParagonIE_Sodium_Core32_Int64 $carry9
    682          */
    683         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
    684         $h1 = $h1->addInt64($carry0);
    685         $h0 = $h0->subInt64($carry0->shiftLeft(26));
    686         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
    687         $h5 = $h5->addInt64($carry4);
    688         $h4 = $h4->subInt64($carry4->shiftLeft(26));
    689 
    690         $carry1 = $h1->addInt(1 << 24)->shiftRight(25);
    691         $h2 = $h2->addInt64($carry1);
    692         $h1 = $h1->subInt64($carry1->shiftLeft(25));
    693         $carry5 = $h5->addInt(1 << 24)->shiftRight(25);
    694         $h6 = $h6->addInt64($carry5);
    695         $h5 = $h5->subInt64($carry5->shiftLeft(25));
    696 
    697         $carry2 = $h2->addInt(1 << 25)->shiftRight(26);
    698         $h3 = $h3->addInt64($carry2);
    699         $h2 = $h2->subInt64($carry2->shiftLeft(26));
    700         $carry6 = $h6->addInt(1 << 25)->shiftRight(26);
    701         $h7 = $h7->addInt64($carry6);
    702         $h6 = $h6->subInt64($carry6->shiftLeft(26));
    703 
    704         $carry3 = $h3->addInt(1 << 24)->shiftRight(25);
    705         $h4 = $h4->addInt64($carry3);
    706         $h3 = $h3->subInt64($carry3->shiftLeft(25));
    707         $carry7 = $h7->addInt(1 << 24)->shiftRight(25);
    708         $h8 = $h8->addInt64($carry7);
    709         $h7 = $h7->subInt64($carry7->shiftLeft(25));
    710 
    711         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
    712         $h5 = $h5->addInt64($carry4);
    713         $h4 = $h4->subInt64($carry4->shiftLeft(26));
    714         $carry8 = $h8->addInt(1 << 25)->shiftRight(26);
    715         $h9 = $h9->addInt64($carry8);
    716         $h8 = $h8->subInt64($carry8->shiftLeft(26));
    717 
    718         $carry9 = $h9->addInt(1 << 24)->shiftRight(25);
    719         $h0 = $h0->addInt64($carry9->mulInt(19, 5));
    720         $h9 = $h9->subInt64($carry9->shiftLeft(25));
    721 
    722         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
    723         $h1 = $h1->addInt64($carry0);
    724         $h0 = $h0->subInt64($carry0->shiftLeft(26));
    725 
    726         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
    727             array(
    728                 $h0->toInt32(),
    729                 $h1->toInt32(),
    730                 $h2->toInt32(),
    731                 $h3->toInt32(),
    732                 $h4->toInt32(),
    733                 $h5->toInt32(),
    734                 $h6->toInt32(),
    735                 $h7->toInt32(),
    736                 $h8->toInt32(),
    737                 $h9->toInt32()
    738             )
    739         );
    740     }
    741 
    742     /**
    743      * Get the negative values for each piece of the field element.
    744      *
    745      * h = -f
    746      *
    747      * @internal You should not use this directly from another application
    748      *
    749      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    750      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    751      * @psalm-suppress MixedAssignment
    752      * @psalm-suppress MixedMethodCall
    753      */
    754     public static function fe_neg(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
    755     {
    756         $h = new ParagonIE_Sodium_Core32_Curve25519_Fe();
    757         for ($i = 0; $i < 10; ++$i) {
    758             $h[$i] = $h[$i]->subInt32($f[$i]);
    759         }
    760         return $h;
    761     }
    762 
    763     /**
    764      * Square a field element
    765      *
    766      * h = f * f
    767      *
    768      * @internal You should not use this directly from another application
    769      *
    770      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    771      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    772      * @throws SodiumException
    773      * @throws TypeError
    774      * @psalm-suppress MixedMethodCall
    775      */
    776     public static function fe_sq(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
    777     {
    778         /** @var ParagonIE_Sodium_Core32_Int64 $f0 */
    779         $f0 = $f[0]->toInt64();
    780         /** @var ParagonIE_Sodium_Core32_Int64 $f1 */
    781         $f1 = $f[1]->toInt64();
    782         /** @var ParagonIE_Sodium_Core32_Int64 $f2 */
    783         $f2 = $f[2]->toInt64();
    784         /** @var ParagonIE_Sodium_Core32_Int64 $f3 */
    785         $f3 = $f[3]->toInt64();
    786         /** @var ParagonIE_Sodium_Core32_Int64 $f4 */
    787         $f4 = $f[4]->toInt64();
    788         /** @var ParagonIE_Sodium_Core32_Int64 $f5 */
    789         $f5 = $f[5]->toInt64();
    790         /** @var ParagonIE_Sodium_Core32_Int64 $f6 */
    791         $f6 = $f[6]->toInt64();
    792         /** @var ParagonIE_Sodium_Core32_Int64 $f7 */
    793         $f7 = $f[7]->toInt64();
    794         /** @var ParagonIE_Sodium_Core32_Int64 $f8 */
    795         $f8 = $f[8]->toInt64();
    796         /** @var ParagonIE_Sodium_Core32_Int64 $f9 */
    797         $f9 = $f[9]->toInt64();
    798 
    799         /** @var ParagonIE_Sodium_Core32_Int64 $f0_2 */
    800         $f0_2 = $f0->shiftLeft(1);
    801         $f1_2 = $f1->shiftLeft(1);
    802         $f2_2 = $f2->shiftLeft(1);
    803         $f3_2 = $f3->shiftLeft(1);
    804         $f4_2 = $f4->shiftLeft(1);
    805         $f5_2 = $f5->shiftLeft(1);
    806         $f6_2 = $f6->shiftLeft(1);
    807         $f7_2 = $f7->shiftLeft(1);
    808         $f5_38 = $f5->mulInt(38, 6);
    809         $f6_19 = $f6->mulInt(19, 5);
    810         $f7_38 = $f7->mulInt(38, 6);
    811         $f8_19 = $f8->mulInt(19, 5);
    812         $f9_38 = $f9->mulInt(38, 6);
    813         /** @var ParagonIE_Sodium_Core32_Int64 $f0f0*/
    814         $f0f0    = $f0->mulInt64($f0, 28);
    815         $f0f1_2  = $f0_2->mulInt64($f1, 28);
    816         $f0f2_2 =  $f0_2->mulInt64($f2, 28);
    817         $f0f3_2 =  $f0_2->mulInt64($f3, 28);
    818         $f0f4_2 =  $f0_2->mulInt64($f4, 28);
    819         $f0f5_2 =  $f0_2->mulInt64($f5, 28);
    820         $f0f6_2 =  $f0_2->mulInt64($f6, 28);
    821         $f0f7_2 =  $f0_2->mulInt64($f7, 28);
    822         $f0f8_2 =  $f0_2->mulInt64($f8, 28);
    823         $f0f9_2 =  $f0_2->mulInt64($f9, 28);
    824 
    825         $f1f1_2 = $f1_2->mulInt64($f1, 28);
    826         $f1f2_2 = $f1_2->mulInt64($f2, 28);
    827         $f1f3_4 = $f1_2->mulInt64($f3_2, 28);
    828         $f1f4_2 = $f1_2->mulInt64($f4, 28);
    829         $f1f5_4 = $f1_2->mulInt64($f5_2, 30);
    830         $f1f6_2 = $f1_2->mulInt64($f6, 28);
    831         $f1f7_4 = $f1_2->mulInt64($f7_2, 28);
    832         $f1f8_2 = $f1_2->mulInt64($f8, 28);
    833         $f1f9_76 = $f9_38->mulInt64($f1_2, 30);
    834 
    835         $f2f2 = $f2->mulInt64($f2, 28);
    836         $f2f3_2 = $f2_2->mulInt64($f3, 28);
    837         $f2f4_2 = $f2_2->mulInt64($f4, 28);
    838         $f2f5_2 = $f2_2->mulInt64($f5, 28);
    839         $f2f6_2 = $f2_2->mulInt64($f6, 28);
    840         $f2f7_2 = $f2_2->mulInt64($f7, 28);
    841         $f2f8_38 = $f8_19->mulInt64($f2_2, 30);
    842         $f2f9_38 = $f9_38->mulInt64($f2, 30);
    843 
    844         $f3f3_2 = $f3_2->mulInt64($f3, 28);
    845         $f3f4_2 = $f3_2->mulInt64($f4, 28);
    846         $f3f5_4 = $f3_2->mulInt64($f5_2, 30);
    847         $f3f6_2 = $f3_2->mulInt64($f6, 28);
    848         $f3f7_76 = $f7_38->mulInt64($f3_2, 30);
    849         $f3f8_38 = $f8_19->mulInt64($f3_2, 30);
    850         $f3f9_76 = $f9_38->mulInt64($f3_2, 30);
    851 
    852         $f4f4 = $f4->mulInt64($f4, 28);
    853         $f4f5_2 = $f4_2->mulInt64($f5, 28);
    854         $f4f6_38 = $f6_19->mulInt64($f4_2, 30);
    855         $f4f7_38 = $f7_38->mulInt64($f4, 30);
    856         $f4f8_38 = $f8_19->mulInt64($f4_2, 30);
    857         $f4f9_38 = $f9_38->mulInt64($f4, 30);
    858 
    859         $f5f5_38 = $f5_38->mulInt64($f5, 30);
    860         $f5f6_38 = $f6_19->mulInt64($f5_2, 30);
    861         $f5f7_76 = $f7_38->mulInt64($f5_2, 30);
    862         $f5f8_38 = $f8_19->mulInt64($f5_2, 30);
    863         $f5f9_76 = $f9_38->mulInt64($f5_2, 30);
    864 
    865         $f6f6_19 = $f6_19->mulInt64($f6, 30);
    866         $f6f7_38 = $f7_38->mulInt64($f6, 30);
    867         $f6f8_38 = $f8_19->mulInt64($f6_2, 30);
    868         $f6f9_38 = $f9_38->mulInt64($f6, 30);
    869 
    870         $f7f7_38 = $f7_38->mulInt64($f7, 28);
    871         $f7f8_38 = $f8_19->mulInt64($f7_2, 30);
    872         $f7f9_76 = $f9_38->mulInt64($f7_2, 30);
    873 
    874         $f8f8_19 = $f8_19->mulInt64($f8, 30);
    875         $f8f9_38 = $f9_38->mulInt64($f8, 30);
    876 
    877         $f9f9_38 = $f9_38->mulInt64($f9, 28);
    878 
    879         $h0 = $f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38);
    880         $h1 = $f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38);
    881         $h2 = $f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19);
    882         $h3 = $f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38);
    883         $h4 = $f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38);
    884         $h5 = $f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38);
    885         $h6 = $f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19);
    886         $h7 = $f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38);
    887         $h8 = $f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38);
    888         $h9 = $f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2);
    889 
    890         /**
    891          * @var ParagonIE_Sodium_Core32_Int64 $h0
    892          * @var ParagonIE_Sodium_Core32_Int64 $h1
    893          * @var ParagonIE_Sodium_Core32_Int64 $h2
    894          * @var ParagonIE_Sodium_Core32_Int64 $h3
    895          * @var ParagonIE_Sodium_Core32_Int64 $h4
    896          * @var ParagonIE_Sodium_Core32_Int64 $h5
    897          * @var ParagonIE_Sodium_Core32_Int64 $h6
    898          * @var ParagonIE_Sodium_Core32_Int64 $h7
    899          * @var ParagonIE_Sodium_Core32_Int64 $h8
    900          * @var ParagonIE_Sodium_Core32_Int64 $h9
    901          */
    902 
    903         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
    904         $h1 = $h1->addInt64($carry0);
    905         $h0 = $h0->subInt64($carry0->shiftLeft(26));
    906 
    907         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
    908         $h5 = $h5->addInt64($carry4);
    909         $h4 = $h4->subInt64($carry4->shiftLeft(26));
    910 
    911         $carry1 = $h1->addInt(1 << 24)->shiftRight(25);
    912         $h2 = $h2->addInt64($carry1);
    913         $h1 = $h1->subInt64($carry1->shiftLeft(25));
    914 
    915         $carry5 = $h5->addInt(1 << 24)->shiftRight(25);
    916         $h6 = $h6->addInt64($carry5);
    917         $h5 = $h5->subInt64($carry5->shiftLeft(25));
    918 
    919         $carry2 = $h2->addInt(1 << 25)->shiftRight(26);
    920         $h3 = $h3->addInt64($carry2);
    921         $h2 = $h2->subInt64($carry2->shiftLeft(26));
    922 
    923         $carry6 = $h6->addInt(1 << 25)->shiftRight(26);
    924         $h7 = $h7->addInt64($carry6);
    925         $h6 = $h6->subInt64($carry6->shiftLeft(26));
    926 
    927         $carry3 = $h3->addInt(1 << 24)->shiftRight(25);
    928         $h4 = $h4->addInt64($carry3);
    929         $h3 = $h3->subInt64($carry3->shiftLeft(25));
    930 
    931         $carry7 = $h7->addInt(1 << 24)->shiftRight(25);
    932         $h8 = $h8->addInt64($carry7);
    933         $h7 = $h7->subInt64($carry7->shiftLeft(25));
    934 
    935         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
    936         $h5 = $h5->addInt64($carry4);
    937         $h4 = $h4->subInt64($carry4->shiftLeft(26));
    938 
    939         $carry8 = $h8->addInt(1 << 25)->shiftRight(26);
    940         $h9 = $h9->addInt64($carry8);
    941         $h8 = $h8->subInt64($carry8->shiftLeft(26));
    942 
    943         $carry9 = $h9->addInt(1 << 24)->shiftRight(25);
    944         $h0 = $h0->addInt64($carry9->mulInt(19, 5));
    945         $h9 = $h9->subInt64($carry9->shiftLeft(25));
    946 
    947         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
    948         $h1 = $h1->addInt64($carry0);
    949         $h0 = $h0->subInt64($carry0->shiftLeft(26));
    950 
    951         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
    952             array(
    953                 $h0->toInt32(),
    954                 $h1->toInt32(),
    955                 $h2->toInt32(),
    956                 $h3->toInt32(),
    957                 $h4->toInt32(),
    958                 $h5->toInt32(),
    959                 $h6->toInt32(),
    960                 $h7->toInt32(),
    961                 $h8->toInt32(),
    962                 $h9->toInt32()
    963             )
    964         );
    965     }
    966 
    967     /**
    968      * Square and double a field element
    969      *
    970      * h = 2 * f * f
    971      *
    972      * @internal You should not use this directly from another application
    973      *
    974      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
    975      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
    976      * @throws SodiumException
    977      * @throws TypeError
    978      * @psalm-suppress MixedMethodCall
    979      */
    980     public static function fe_sq2(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
    981     {
    982         /** @var ParagonIE_Sodium_Core32_Int64 $f0 */
    983         $f0 = $f[0]->toInt64();
    984         /** @var ParagonIE_Sodium_Core32_Int64 $f1 */
    985         $f1 = $f[1]->toInt64();
    986         /** @var ParagonIE_Sodium_Core32_Int64 $f2 */
    987         $f2 = $f[2]->toInt64();
    988         /** @var ParagonIE_Sodium_Core32_Int64 $f3 */
    989         $f3 = $f[3]->toInt64();
    990         /** @var ParagonIE_Sodium_Core32_Int64 $f4 */
    991         $f4 = $f[4]->toInt64();
    992         /** @var ParagonIE_Sodium_Core32_Int64 $f5 */
    993         $f5 = $f[5]->toInt64();
    994         /** @var ParagonIE_Sodium_Core32_Int64 $f6 */
    995         $f6 = $f[6]->toInt64();
    996         /** @var ParagonIE_Sodium_Core32_Int64 $f7 */
    997         $f7 = $f[7]->toInt64();
    998         /** @var ParagonIE_Sodium_Core32_Int64 $f8 */
    999         $f8 = $f[8]->toInt64();
   1000         /** @var ParagonIE_Sodium_Core32_Int64 $f9 */
   1001         $f9 = $f[9]->toInt64();
   1002 
   1003         $f0_2 = $f0->shiftLeft(1);
   1004         $f1_2 = $f1->shiftLeft(1);
   1005         $f2_2 = $f2->shiftLeft(1);
   1006         $f3_2 = $f3->shiftLeft(1);
   1007         $f4_2 = $f4->shiftLeft(1);
   1008         $f5_2 = $f5->shiftLeft(1);
   1009         $f6_2 = $f6->shiftLeft(1);
   1010         $f7_2 = $f7->shiftLeft(1);
   1011         $f5_38 = $f5->mulInt(38, 6); /* 1.959375*2^30 */
   1012         $f6_19 = $f6->mulInt(19, 5); /* 1.959375*2^30 */
   1013         $f7_38 = $f7->mulInt(38, 6); /* 1.959375*2^30 */
   1014         $f8_19 = $f8->mulInt(19, 5); /* 1.959375*2^30 */
   1015         $f9_38 = $f9->mulInt(38, 6); /* 1.959375*2^30 */
   1016         $f0f0 = $f0->mulInt64($f0, 28);
   1017         $f0f1_2 = $f0_2->mulInt64($f1, 28);
   1018         $f0f2_2 = $f0_2->mulInt64($f2, 28);
   1019         $f0f3_2 = $f0_2->mulInt64($f3, 28);
   1020         $f0f4_2 = $f0_2->mulInt64($f4, 28);
   1021         $f0f5_2 = $f0_2->mulInt64($f5, 28);
   1022         $f0f6_2 = $f0_2->mulInt64($f6, 28);
   1023         $f0f7_2 = $f0_2->mulInt64($f7, 28);
   1024         $f0f8_2 = $f0_2->mulInt64($f8, 28);
   1025         $f0f9_2 = $f0_2->mulInt64($f9, 28);
   1026         $f1f1_2 = $f1_2->mulInt64($f1, 28);
   1027         $f1f2_2 = $f1_2->mulInt64($f2, 28);
   1028         $f1f3_4 = $f1_2->mulInt64($f3_2, 29);
   1029         $f1f4_2 = $f1_2->mulInt64($f4, 28);
   1030         $f1f5_4 = $f1_2->mulInt64($f5_2, 29);
   1031         $f1f6_2 = $f1_2->mulInt64($f6, 28);
   1032         $f1f7_4 = $f1_2->mulInt64($f7_2, 29);
   1033         $f1f8_2 = $f1_2->mulInt64($f8, 28);
   1034         $f1f9_76 = $f9_38->mulInt64($f1_2, 29);
   1035         $f2f2 = $f2->mulInt64($f2, 28);
   1036         $f2f3_2 = $f2_2->mulInt64($f3, 28);
   1037         $f2f4_2 = $f2_2->mulInt64($f4, 28);
   1038         $f2f5_2 = $f2_2->mulInt64($f5, 28);
   1039         $f2f6_2 = $f2_2->mulInt64($f6, 28);
   1040         $f2f7_2 = $f2_2->mulInt64($f7, 28);
   1041         $f2f8_38 = $f8_19->mulInt64($f2_2, 29);
   1042         $f2f9_38 = $f9_38->mulInt64($f2, 29);
   1043         $f3f3_2 = $f3_2->mulInt64($f3, 28);
   1044         $f3f4_2 = $f3_2->mulInt64($f4, 28);
   1045         $f3f5_4 = $f3_2->mulInt64($f5_2, 28);
   1046         $f3f6_2 = $f3_2->mulInt64($f6, 28);
   1047         $f3f7_76 = $f7_38->mulInt64($f3_2, 29);
   1048         $f3f8_38 = $f8_19->mulInt64($f3_2, 29);
   1049         $f3f9_76 = $f9_38->mulInt64($f3_2, 29);
   1050         $f4f4 = $f4->mulInt64($f4, 28);
   1051         $f4f5_2 = $f4_2->mulInt64($f5, 28);
   1052         $f4f6_38 = $f6_19->mulInt64($f4_2, 29);
   1053         $f4f7_38 = $f7_38->mulInt64($f4, 29);
   1054         $f4f8_38 = $f8_19->mulInt64($f4_2, 29);
   1055         $f4f9_38 = $f9_38->mulInt64($f4, 29);
   1056         $f5f5_38 = $f5_38->mulInt64($f5, 29);
   1057         $f5f6_38 = $f6_19->mulInt64($f5_2, 29);
   1058         $f5f7_76 = $f7_38->mulInt64($f5_2, 29);
   1059         $f5f8_38 = $f8_19->mulInt64($f5_2, 29);
   1060         $f5f9_76 = $f9_38->mulInt64($f5_2, 29);
   1061         $f6f6_19 = $f6_19->mulInt64($f6, 29);
   1062         $f6f7_38 = $f7_38->mulInt64($f6, 29);
   1063         $f6f8_38 = $f8_19->mulInt64($f6_2, 29);
   1064         $f6f9_38 = $f9_38->mulInt64($f6, 29);
   1065         $f7f7_38 = $f7_38->mulInt64($f7, 29);
   1066         $f7f8_38 = $f8_19->mulInt64($f7_2, 29);
   1067         $f7f9_76 = $f9_38->mulInt64($f7_2, 29);
   1068         $f8f8_19 = $f8_19->mulInt64($f8, 29);
   1069         $f8f9_38 = $f9_38->mulInt64($f8, 29);
   1070         $f9f9_38 = $f9_38->mulInt64($f9, 29);
   1071 
   1072         $h0 = $f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38);
   1073         $h1 = $f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38);
   1074         $h2 = $f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19);
   1075         $h3 = $f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38);
   1076         $h4 = $f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38);
   1077         $h5 = $f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38);
   1078         $h6 = $f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19);
   1079         $h7 = $f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38);
   1080         $h8 = $f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38);
   1081         $h9 = $f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2);
   1082 
   1083         /**
   1084          * @var ParagonIE_Sodium_Core32_Int64 $h0
   1085          * @var ParagonIE_Sodium_Core32_Int64 $h1
   1086          * @var ParagonIE_Sodium_Core32_Int64 $h2
   1087          * @var ParagonIE_Sodium_Core32_Int64 $h3
   1088          * @var ParagonIE_Sodium_Core32_Int64 $h4
   1089          * @var ParagonIE_Sodium_Core32_Int64 $h5
   1090          * @var ParagonIE_Sodium_Core32_Int64 $h6
   1091          * @var ParagonIE_Sodium_Core32_Int64 $h7
   1092          * @var ParagonIE_Sodium_Core32_Int64 $h8
   1093          * @var ParagonIE_Sodium_Core32_Int64 $h9
   1094          */
   1095         $h0 = $h0->shiftLeft(1);
   1096         $h1 = $h1->shiftLeft(1);
   1097         $h2 = $h2->shiftLeft(1);
   1098         $h3 = $h3->shiftLeft(1);
   1099         $h4 = $h4->shiftLeft(1);
   1100         $h5 = $h5->shiftLeft(1);
   1101         $h6 = $h6->shiftLeft(1);
   1102         $h7 = $h7->shiftLeft(1);
   1103         $h8 = $h8->shiftLeft(1);
   1104         $h9 = $h9->shiftLeft(1);
   1105 
   1106         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
   1107         $h1 = $h1->addInt64($carry0);
   1108         $h0 = $h0->subInt64($carry0->shiftLeft(26));
   1109         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
   1110         $h5 = $h5->addInt64($carry4);
   1111         $h4 = $h4->subInt64($carry4->shiftLeft(26));
   1112 
   1113         $carry1 = $h1->addInt(1 << 24)->shiftRight(25);
   1114         $h2 = $h2->addInt64($carry1);
   1115         $h1 = $h1->subInt64($carry1->shiftLeft(25));
   1116         $carry5 = $h5->addInt(1 << 24)->shiftRight(25);
   1117         $h6 = $h6->addInt64($carry5);
   1118         $h5 = $h5->subInt64($carry5->shiftLeft(25));
   1119 
   1120         $carry2 = $h2->addInt(1 << 25)->shiftRight(26);
   1121         $h3 = $h3->addInt64($carry2);
   1122         $h2 = $h2->subInt64($carry2->shiftLeft(26));
   1123         $carry6 = $h6->addInt(1 << 25)->shiftRight(26);
   1124         $h7 = $h7->addInt64($carry6);
   1125         $h6 = $h6->subInt64($carry6->shiftLeft(26));
   1126 
   1127         $carry3 = $h3->addInt(1 << 24)->shiftRight(25);
   1128         $h4 = $h4->addInt64($carry3);
   1129         $h3 = $h3->subInt64($carry3->shiftLeft(25));
   1130         $carry7 = $h7->addInt(1 << 24)->shiftRight(25);
   1131         $h8 = $h8->addInt64($carry7);
   1132         $h7 = $h7->subInt64($carry7->shiftLeft(25));
   1133 
   1134         $carry4 = $h4->addInt(1 << 25)->shiftRight(26);
   1135         $h5 = $h5->addInt64($carry4);
   1136         $h4 = $h4->subInt64($carry4->shiftLeft(26));
   1137         $carry8 = $h8->addInt(1 << 25)->shiftRight(26);
   1138         $h9 = $h9->addInt64($carry8);
   1139         $h8 = $h8->subInt64($carry8->shiftLeft(26));
   1140 
   1141         $carry9 = $h9->addInt(1 << 24)->shiftRight(25);
   1142         $h0 = $h0->addInt64($carry9->mulInt(19, 5));
   1143         $h9 = $h9->subInt64($carry9->shiftLeft(25));
   1144 
   1145         $carry0 = $h0->addInt(1 << 25)->shiftRight(26);
   1146         $h1 = $h1->addInt64($carry0);
   1147         $h0 = $h0->subInt64($carry0->shiftLeft(26));
   1148 
   1149         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1150             array(
   1151                 $h0->toInt32(),
   1152                 $h1->toInt32(),
   1153                 $h2->toInt32(),
   1154                 $h3->toInt32(),
   1155                 $h4->toInt32(),
   1156                 $h5->toInt32(),
   1157                 $h6->toInt32(),
   1158                 $h7->toInt32(),
   1159                 $h8->toInt32(),
   1160                 $h9->toInt32()
   1161             )
   1162         );
   1163     }
   1164 
   1165     /**
   1166      * @internal You should not use this directly from another application
   1167      *
   1168      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $Z
   1169      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
   1170      * @throws SodiumException
   1171      * @throws TypeError
   1172      */
   1173     public static function fe_invert(ParagonIE_Sodium_Core32_Curve25519_Fe $Z)
   1174     {
   1175         $z = clone $Z;
   1176         $t0 = self::fe_sq($z);
   1177         $t1 = self::fe_sq($t0);
   1178         $t1 = self::fe_sq($t1);
   1179         $t1 = self::fe_mul($z, $t1);
   1180         $t0 = self::fe_mul($t0, $t1);
   1181         $t2 = self::fe_sq($t0);
   1182         $t1 = self::fe_mul($t1, $t2);
   1183         $t2 = self::fe_sq($t1);
   1184         for ($i = 1; $i < 5; ++$i) {
   1185             $t2 = self::fe_sq($t2);
   1186         }
   1187         $t1 = self::fe_mul($t2, $t1);
   1188         $t2 = self::fe_sq($t1);
   1189         for ($i = 1; $i < 10; ++$i) {
   1190             $t2 = self::fe_sq($t2);
   1191         }
   1192         $t2 = self::fe_mul($t2, $t1);
   1193         $t3 = self::fe_sq($t2);
   1194         for ($i = 1; $i < 20; ++$i) {
   1195             $t3 = self::fe_sq($t3);
   1196         }
   1197         $t2 = self::fe_mul($t3, $t2);
   1198         $t2 = self::fe_sq($t2);
   1199         for ($i = 1; $i < 10; ++$i) {
   1200             $t2 = self::fe_sq($t2);
   1201         }
   1202         $t1 = self::fe_mul($t2, $t1);
   1203         $t2 = self::fe_sq($t1);
   1204         for ($i = 1; $i < 50; ++$i) {
   1205             $t2 = self::fe_sq($t2);
   1206         }
   1207         $t2 = self::fe_mul($t2, $t1);
   1208         $t3 = self::fe_sq($t2);
   1209         for ($i = 1; $i < 100; ++$i) {
   1210             $t3 = self::fe_sq($t3);
   1211         }
   1212         $t2 = self::fe_mul($t3, $t2);
   1213         $t2 = self::fe_sq($t2);
   1214         for ($i = 1; $i < 50; ++$i) {
   1215             $t2 = self::fe_sq($t2);
   1216         }
   1217         $t1 = self::fe_mul($t2, $t1);
   1218         $t1 = self::fe_sq($t1);
   1219         for ($i = 1; $i < 5; ++$i) {
   1220             $t1 = self::fe_sq($t1);
   1221         }
   1222         return self::fe_mul($t1, $t0);
   1223     }
   1224 
   1225     /**
   1226      * @internal You should not use this directly from another application
   1227      *
   1228      * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
   1229      *
   1230      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $z
   1231      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
   1232      * @throws SodiumException
   1233      * @throws TypeError
   1234      */
   1235     public static function fe_pow22523(ParagonIE_Sodium_Core32_Curve25519_Fe $z)
   1236     {
   1237         # fe_sq(t0, z);
   1238         # fe_sq(t1, t0);
   1239         # fe_sq(t1, t1);
   1240         # fe_mul(t1, z, t1);
   1241         # fe_mul(t0, t0, t1);
   1242         # fe_sq(t0, t0);
   1243         # fe_mul(t0, t1, t0);
   1244         # fe_sq(t1, t0);
   1245         $t0 = self::fe_sq($z);
   1246         $t1 = self::fe_sq($t0);
   1247         $t1 = self::fe_sq($t1);
   1248         $t1 = self::fe_mul($z, $t1);
   1249         $t0 = self::fe_mul($t0, $t1);
   1250         $t0 = self::fe_sq($t0);
   1251         $t0 = self::fe_mul($t1, $t0);
   1252         $t1 = self::fe_sq($t0);
   1253 
   1254         # for (i = 1; i < 5; ++i) {
   1255         #     fe_sq(t1, t1);
   1256         # }
   1257         for ($i = 1; $i < 5; ++$i) {
   1258             $t1 = self::fe_sq($t1);
   1259         }
   1260 
   1261         # fe_mul(t0, t1, t0);
   1262         # fe_sq(t1, t0);
   1263         $t0 = self::fe_mul($t1, $t0);
   1264         $t1 = self::fe_sq($t0);
   1265 
   1266         # for (i = 1; i < 10; ++i) {
   1267         #     fe_sq(t1, t1);
   1268         # }
   1269         for ($i = 1; $i < 10; ++$i) {
   1270             $t1 = self::fe_sq($t1);
   1271         }
   1272 
   1273         # fe_mul(t1, t1, t0);
   1274         # fe_sq(t2, t1);
   1275         $t1 = self::fe_mul($t1, $t0);
   1276         $t2 = self::fe_sq($t1);
   1277 
   1278         # for (i = 1; i < 20; ++i) {
   1279         #     fe_sq(t2, t2);
   1280         # }
   1281         for ($i = 1; $i < 20; ++$i) {
   1282             $t2 = self::fe_sq($t2);
   1283         }
   1284 
   1285         # fe_mul(t1, t2, t1);
   1286         # fe_sq(t1, t1);
   1287         $t1 = self::fe_mul($t2, $t1);
   1288         $t1 = self::fe_sq($t1);
   1289 
   1290         # for (i = 1; i < 10; ++i) {
   1291         #     fe_sq(t1, t1);
   1292         # }
   1293         for ($i = 1; $i < 10; ++$i) {
   1294             $t1 = self::fe_sq($t1);
   1295         }
   1296 
   1297         # fe_mul(t0, t1, t0);
   1298         # fe_sq(t1, t0);
   1299         $t0 = self::fe_mul($t1, $t0);
   1300         $t1 = self::fe_sq($t0);
   1301 
   1302         # for (i = 1; i < 50; ++i) {
   1303         #     fe_sq(t1, t1);
   1304         # }
   1305         for ($i = 1; $i < 50; ++$i) {
   1306             $t1 = self::fe_sq($t1);
   1307         }
   1308 
   1309         # fe_mul(t1, t1, t0);
   1310         # fe_sq(t2, t1);
   1311         $t1 = self::fe_mul($t1, $t0);
   1312         $t2 = self::fe_sq($t1);
   1313 
   1314         # for (i = 1; i < 100; ++i) {
   1315         #     fe_sq(t2, t2);
   1316         # }
   1317         for ($i = 1; $i < 100; ++$i) {
   1318             $t2 = self::fe_sq($t2);
   1319         }
   1320 
   1321         # fe_mul(t1, t2, t1);
   1322         # fe_sq(t1, t1);
   1323         $t1 = self::fe_mul($t2, $t1);
   1324         $t1 = self::fe_sq($t1);
   1325 
   1326         # for (i = 1; i < 50; ++i) {
   1327         #     fe_sq(t1, t1);
   1328         # }
   1329         for ($i = 1; $i < 50; ++$i) {
   1330             $t1 = self::fe_sq($t1);
   1331         }
   1332 
   1333         # fe_mul(t0, t1, t0);
   1334         # fe_sq(t0, t0);
   1335         # fe_sq(t0, t0);
   1336         # fe_mul(out, t0, z);
   1337         $t0 = self::fe_mul($t1, $t0);
   1338         $t0 = self::fe_sq($t0);
   1339         $t0 = self::fe_sq($t0);
   1340         return self::fe_mul($t0, $z);
   1341     }
   1342 
   1343     /**
   1344      * Subtract two field elements.
   1345      *
   1346      * h = f - g
   1347      *
   1348      * Preconditions:
   1349      * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
   1350      * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
   1351      *
   1352      * Postconditions:
   1353      * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
   1354      *
   1355      * @internal You should not use this directly from another application
   1356      *
   1357      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
   1358      * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
   1359      * @return ParagonIE_Sodium_Core32_Curve25519_Fe
   1360      * @throws SodiumException
   1361      * @throws TypeError
   1362      * @psalm-suppress MixedMethodCall
   1363      * @psalm-suppress MixedTypeCoercion
   1364      */
   1365     public static function fe_sub(ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g)
   1366     {
   1367         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1368             array(
   1369                 $f[0]->subInt32($g[0]),
   1370                 $f[1]->subInt32($g[1]),
   1371                 $f[2]->subInt32($g[2]),
   1372                 $f[3]->subInt32($g[3]),
   1373                 $f[4]->subInt32($g[4]),
   1374                 $f[5]->subInt32($g[5]),
   1375                 $f[6]->subInt32($g[6]),
   1376                 $f[7]->subInt32($g[7]),
   1377                 $f[8]->subInt32($g[8]),
   1378                 $f[9]->subInt32($g[9])
   1379             )
   1380         );
   1381     }
   1382 
   1383     /**
   1384      * Add two group elements.
   1385      *
   1386      * r = p + q
   1387      *
   1388      * @internal You should not use this directly from another application
   1389      *
   1390      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1391      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
   1392      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
   1393      * @throws SodiumException
   1394      * @throws TypeError
   1395      */
   1396     public static function ge_add(
   1397         ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
   1398         ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
   1399     ) {
   1400         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
   1401         $r->X = self::fe_add($p->Y, $p->X);
   1402         $r->Y = self::fe_sub($p->Y, $p->X);
   1403         $r->Z = self::fe_mul($r->X, $q->YplusX);
   1404         $r->Y = self::fe_mul($r->Y, $q->YminusX);
   1405         $r->T = self::fe_mul($q->T2d, $p->T);
   1406         $r->X = self::fe_mul($p->Z, $q->Z);
   1407         $t0   = self::fe_add($r->X, $r->X);
   1408         $r->X = self::fe_sub($r->Z, $r->Y);
   1409         $r->Y = self::fe_add($r->Z, $r->Y);
   1410         $r->Z = self::fe_add($t0, $r->T);
   1411         $r->T = self::fe_sub($t0, $r->T);
   1412         return $r;
   1413     }
   1414 
   1415     /**
   1416      * @internal You should not use this directly from another application
   1417      *
   1418      * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
   1419      * @param string $a
   1420      * @return array<int, mixed>
   1421      * @throws SodiumException
   1422      * @throws TypeError
   1423      * @psalm-suppress MixedArrayOffset
   1424      */
   1425     public static function slide($a)
   1426     {
   1427         if (self::strlen($a) < 256) {
   1428             if (self::strlen($a) < 16) {
   1429                 $a = str_pad($a, 256, '0', STR_PAD_RIGHT);
   1430             }
   1431         }
   1432         /** @var array<int, int> $r */
   1433         $r = array();
   1434         for ($i = 0; $i < 256; ++$i) {
   1435             $r[$i] = (int) (1 &
   1436                 (
   1437                     self::chrToInt($a[$i >> 3])
   1438                         >>
   1439                     ($i & 7)
   1440                 )
   1441             );
   1442         }
   1443 
   1444         for ($i = 0;$i < 256;++$i) {
   1445             if ($r[$i]) {
   1446                 for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
   1447                     if ($r[$i + $b]) {
   1448                         if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
   1449                             $r[$i] += $r[$i + $b] << $b;
   1450                             $r[$i + $b] = 0;
   1451                         } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
   1452                             $r[$i] -= $r[$i + $b] << $b;
   1453                             for ($k = $i + $b; $k < 256; ++$k) {
   1454                                 if (!$r[$k]) {
   1455                                     $r[$k] = 1;
   1456                                     break;
   1457                                 }
   1458                                 $r[$k] = 0;
   1459                             }
   1460                         } else {
   1461                             break;
   1462                         }
   1463                     }
   1464                 }
   1465             }
   1466         }
   1467         return $r;
   1468     }
   1469 
   1470     /**
   1471      * @internal You should not use this directly from another application
   1472      *
   1473      * @param string $s
   1474      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
   1475      * @throws SodiumException
   1476      * @throws TypeError
   1477      */
   1478     public static function ge_frombytes_negate_vartime($s)
   1479     {
   1480         static $d = null;
   1481         if (!$d) {
   1482             /** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */
   1483             $d = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1484                 array(
   1485                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[0]),
   1486                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[1]),
   1487                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[2]),
   1488                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[3]),
   1489                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[4]),
   1490                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[5]),
   1491                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[6]),
   1492                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[7]),
   1493                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[8]),
   1494                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[9])
   1495                 )
   1496             );
   1497         }
   1498 
   1499         # fe_frombytes(h->Y,s);
   1500         # fe_1(h->Z);
   1501         $h = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(
   1502             self::fe_0(),
   1503             self::fe_frombytes($s),
   1504             self::fe_1()
   1505         );
   1506 
   1507         # fe_sq(u,h->Y);
   1508         # fe_mul(v,u,d);
   1509         # fe_sub(u,u,h->Z);       /* u = y^2-1 */
   1510         # fe_add(v,v,h->Z);       /* v = dy^2+1 */
   1511         $u = self::fe_sq($h->Y);
   1512         /** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */
   1513         $v = self::fe_mul($u, $d);
   1514         $u = self::fe_sub($u, $h->Z); /* u =  y^2 - 1 */
   1515         $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
   1516 
   1517         # fe_sq(v3,v);
   1518         # fe_mul(v3,v3,v);        /* v3 = v^3 */
   1519         # fe_sq(h->X,v3);
   1520         # fe_mul(h->X,h->X,v);
   1521         # fe_mul(h->X,h->X,u);    /* x = uv^7 */
   1522         $v3 = self::fe_sq($v);
   1523         $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
   1524         $h->X = self::fe_sq($v3);
   1525         $h->X = self::fe_mul($h->X, $v);
   1526         $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
   1527 
   1528         # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
   1529         # fe_mul(h->X,h->X,v3);
   1530         # fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
   1531         $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
   1532         $h->X = self::fe_mul($h->X, $v3);
   1533         $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
   1534 
   1535         # fe_sq(vxx,h->X);
   1536         # fe_mul(vxx,vxx,v);
   1537         # fe_sub(check,vxx,u);    /* vx^2-u */
   1538         $vxx = self::fe_sq($h->X);
   1539         $vxx = self::fe_mul($vxx, $v);
   1540         $check = self::fe_sub($vxx, $u); /* vx^2 - u */
   1541 
   1542         # if (fe_isnonzero(check)) {
   1543         #     fe_add(check,vxx,u);  /* vx^2+u */
   1544         #     if (fe_isnonzero(check)) {
   1545         #         return -1;
   1546         #     }
   1547         #     fe_mul(h->X,h->X,sqrtm1);
   1548         # }
   1549         if (self::fe_isnonzero($check)) {
   1550             $check = self::fe_add($vxx, $u); /* vx^2 + u */
   1551             if (self::fe_isnonzero($check)) {
   1552                 throw new RangeException('Internal check failed.');
   1553             }
   1554             $h->X = self::fe_mul(
   1555                 $h->X,
   1556                 ParagonIE_Sodium_Core32_Curve25519_Fe::fromIntArray(self::$sqrtm1)
   1557             );
   1558         }
   1559 
   1560         # if (fe_isnegative(h->X) == (s[31] >> 7)) {
   1561         #     fe_neg(h->X,h->X);
   1562         # }
   1563         $i = self::chrToInt($s[31]);
   1564         if (self::fe_isnegative($h->X) === ($i >> 7)) {
   1565             $h->X = self::fe_neg($h->X);
   1566         }
   1567 
   1568         # fe_mul(h->T,h->X,h->Y);
   1569         $h->T = self::fe_mul($h->X, $h->Y);
   1570         return $h;
   1571     }
   1572 
   1573     /**
   1574      * @internal You should not use this directly from another application
   1575      *
   1576      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R
   1577      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1578      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
   1579      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
   1580      * @throws SodiumException
   1581      * @throws TypeError
   1582      */
   1583     public static function ge_madd(
   1584         ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R,
   1585         ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
   1586         ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
   1587     ) {
   1588         $r = clone $R;
   1589         $r->X = self::fe_add($p->Y, $p->X);
   1590         $r->Y = self::fe_sub($p->Y, $p->X);
   1591         $r->Z = self::fe_mul($r->X, $q->yplusx);
   1592         $r->Y = self::fe_mul($r->Y, $q->yminusx);
   1593         $r->T = self::fe_mul($q->xy2d, $p->T);
   1594         $t0 = self::fe_add(clone $p->Z, clone $p->Z);
   1595         $r->X = self::fe_sub($r->Z, $r->Y);
   1596         $r->Y = self::fe_add($r->Z, $r->Y);
   1597         $r->Z = self::fe_add($t0, $r->T);
   1598         $r->T = self::fe_sub($t0, $r->T);
   1599 
   1600         return $r;
   1601     }
   1602 
   1603     /**
   1604      * @internal You should not use this directly from another application
   1605      *
   1606      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R
   1607      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1608      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
   1609      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
   1610      * @throws SodiumException
   1611      * @throws TypeError
   1612      */
   1613     public static function ge_msub(
   1614         ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R,
   1615         ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
   1616         ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
   1617     ) {
   1618         $r = clone $R;
   1619 
   1620         $r->X = self::fe_add($p->Y, $p->X);
   1621         $r->Y = self::fe_sub($p->Y, $p->X);
   1622         $r->Z = self::fe_mul($r->X, $q->yminusx);
   1623         $r->Y = self::fe_mul($r->Y, $q->yplusx);
   1624         $r->T = self::fe_mul($q->xy2d, $p->T);
   1625         $t0 = self::fe_add($p->Z, $p->Z);
   1626         $r->X = self::fe_sub($r->Z, $r->Y);
   1627         $r->Y = self::fe_add($r->Z, $r->Y);
   1628         $r->Z = self::fe_sub($t0, $r->T);
   1629         $r->T = self::fe_add($t0, $r->T);
   1630 
   1631         return $r;
   1632     }
   1633 
   1634     /**
   1635      * @internal You should not use this directly from another application
   1636      *
   1637      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p
   1638      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
   1639      * @throws SodiumException
   1640      * @throws TypeError
   1641      */
   1642     public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p)
   1643     {
   1644         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P2();
   1645         $r->X = self::fe_mul($p->X, $p->T);
   1646         $r->Y = self::fe_mul($p->Y, $p->Z);
   1647         $r->Z = self::fe_mul($p->Z, $p->T);
   1648         return $r;
   1649     }
   1650 
   1651     /**
   1652      * @internal You should not use this directly from another application
   1653      *
   1654      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p
   1655      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
   1656      * @throws SodiumException
   1657      * @throws TypeError
   1658      */
   1659     public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p)
   1660     {
   1661         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3();
   1662         $r->X = self::fe_mul($p->X, $p->T);
   1663         $r->Y = self::fe_mul($p->Y, $p->Z);
   1664         $r->Z = self::fe_mul($p->Z, $p->T);
   1665         $r->T = self::fe_mul($p->X, $p->Y);
   1666         return $r;
   1667     }
   1668 
   1669     /**
   1670      * @internal You should not use this directly from another application
   1671      *
   1672      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
   1673      * @throws SodiumException
   1674      * @throws TypeError
   1675      */
   1676     public static function ge_p2_0()
   1677     {
   1678         return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(
   1679             self::fe_0(),
   1680             self::fe_1(),
   1681             self::fe_1()
   1682         );
   1683     }
   1684 
   1685     /**
   1686      * @internal You should not use this directly from another application
   1687      *
   1688      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p
   1689      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
   1690      * @throws SodiumException
   1691      * @throws TypeError
   1692      */
   1693     public static function ge_p2_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p)
   1694     {
   1695         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
   1696 
   1697         $r->X = self::fe_sq($p->X);
   1698         $r->Z = self::fe_sq($p->Y);
   1699         $r->T = self::fe_sq2($p->Z);
   1700         $r->Y = self::fe_add($p->X, $p->Y);
   1701         $t0   = self::fe_sq($r->Y);
   1702         $r->Y = self::fe_add($r->Z, $r->X);
   1703         $r->Z = self::fe_sub($r->Z, $r->X);
   1704         $r->X = self::fe_sub($t0, $r->Y);
   1705         $r->T = self::fe_sub($r->T, $r->Z);
   1706 
   1707         return $r;
   1708     }
   1709 
   1710     /**
   1711      * @internal You should not use this directly from another application
   1712      *
   1713      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
   1714      * @throws SodiumException
   1715      * @throws TypeError
   1716      */
   1717     public static function ge_p3_0()
   1718     {
   1719         return new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(
   1720             self::fe_0(),
   1721             self::fe_1(),
   1722             self::fe_1(),
   1723             self::fe_0()
   1724         );
   1725     }
   1726 
   1727     /**
   1728      * @internal You should not use this directly from another application
   1729      *
   1730      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1731      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
   1732      * @throws SodiumException
   1733      * @throws TypeError
   1734      */
   1735     public static function ge_p3_to_cached(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
   1736     {
   1737         static $d2 = null;
   1738         if ($d2 === null) {
   1739             $d2 = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1740                 array(
   1741                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[0]),
   1742                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[1]),
   1743                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[2]),
   1744                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[3]),
   1745                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[4]),
   1746                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[5]),
   1747                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[6]),
   1748                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[7]),
   1749                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[8]),
   1750                     ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[9])
   1751                 )
   1752             );
   1753         }
   1754         /** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d2 */
   1755         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached();
   1756         $r->YplusX = self::fe_add($p->Y, $p->X);
   1757         $r->YminusX = self::fe_sub($p->Y, $p->X);
   1758         $r->Z = self::fe_copy($p->Z);
   1759         $r->T2d = self::fe_mul($p->T, $d2);
   1760         return $r;
   1761     }
   1762 
   1763     /**
   1764      * @internal You should not use this directly from another application
   1765      *
   1766      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1767      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
   1768      */
   1769     public static function ge_p3_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
   1770     {
   1771         return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(
   1772             $p->X,
   1773             $p->Y,
   1774             $p->Z
   1775         );
   1776     }
   1777 
   1778     /**
   1779      * @internal You should not use this directly from another application
   1780      *
   1781      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h
   1782      * @return string
   1783      * @throws SodiumException
   1784      * @throws TypeError
   1785      */
   1786     public static function ge_p3_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h)
   1787     {
   1788         $recip = self::fe_invert($h->Z);
   1789         $x = self::fe_mul($h->X, $recip);
   1790         $y = self::fe_mul($h->Y, $recip);
   1791         $s = self::fe_tobytes($y);
   1792         $s[31] = self::intToChr(
   1793             self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
   1794         );
   1795         return $s;
   1796     }
   1797 
   1798     /**
   1799      * @internal You should not use this directly from another application
   1800      *
   1801      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1802      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
   1803      * @throws SodiumException
   1804      * @throws TypeError
   1805      */
   1806     public static function ge_p3_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
   1807     {
   1808         $q = self::ge_p3_to_p2($p);
   1809         return self::ge_p2_dbl($q);
   1810     }
   1811 
   1812     /**
   1813      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
   1814      * @throws SodiumException
   1815      * @throws TypeError
   1816      */
   1817     public static function ge_precomp_0()
   1818     {
   1819         return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
   1820             self::fe_1(),
   1821             self::fe_1(),
   1822             self::fe_0()
   1823         );
   1824     }
   1825 
   1826     /**
   1827      * @internal You should not use this directly from another application
   1828      *
   1829      * @param int $b
   1830      * @param int $c
   1831      * @return int
   1832      * @psalm-suppress MixedReturnStatement
   1833      */
   1834     public static function equal($b, $c)
   1835     {
   1836         return (int) ((($b ^ $c) - 1 & 0xffffffff) >> 31);
   1837     }
   1838 
   1839     /**
   1840      * @internal You should not use this directly from another application
   1841      *
   1842      * @param string|int $char
   1843      * @return int (1 = yes, 0 = no)
   1844      * @throws SodiumException
   1845      * @throws TypeError
   1846      */
   1847     public static function negative($char)
   1848     {
   1849         if (is_int($char)) {
   1850             return $char < 0 ? 1 : 0;
   1851         }
   1852         /** @var string $char */
   1853         /** @var int $x */
   1854         $x = self::chrToInt(self::substr($char, 0, 1));
   1855         return (int) ($x >> 31);
   1856     }
   1857 
   1858     /**
   1859      * Conditional move
   1860      *
   1861      * @internal You should not use this directly from another application
   1862      *
   1863      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t
   1864      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u
   1865      * @param int $b
   1866      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
   1867      * @throws SodiumException
   1868      * @throws TypeError
   1869      */
   1870     public static function cmov(
   1871         ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t,
   1872         ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u,
   1873         $b
   1874     ) {
   1875         if (!is_int($b)) {
   1876             throw new InvalidArgumentException('Expected an integer.');
   1877         }
   1878         return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
   1879             self::fe_cmov($t->yplusx, $u->yplusx, $b),
   1880             self::fe_cmov($t->yminusx, $u->yminusx, $b),
   1881             self::fe_cmov($t->xy2d, $u->xy2d, $b)
   1882         );
   1883     }
   1884 
   1885     /**
   1886      * @internal You should not use this directly from another application
   1887      *
   1888      * @param int $pos
   1889      * @param int $b
   1890      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
   1891      * @throws SodiumException
   1892      * @throws TypeError
   1893      * @psalm-suppress MixedArrayAccess
   1894      * @psalm-suppress MixedArrayOffset
   1895      * @psalm-suppress MixedArgument
   1896      */
   1897     public static function ge_select($pos = 0, $b = 0)
   1898     {
   1899         static $base = null;
   1900         if ($base === null) {
   1901             $base = array();
   1902             foreach (self::$base as $i => $bas) {
   1903                 for ($j = 0; $j < 8; ++$j) {
   1904                     $base[$i][$j] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
   1905                         ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1906                             array(
   1907                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][0]),
   1908                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][1]),
   1909                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][2]),
   1910                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][3]),
   1911                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][4]),
   1912                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][5]),
   1913                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][6]),
   1914                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][7]),
   1915                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][8]),
   1916                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][9])
   1917                             )
   1918                         ),
   1919                         ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1920                             array(
   1921                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][0]),
   1922                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][1]),
   1923                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][2]),
   1924                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][3]),
   1925                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][4]),
   1926                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][5]),
   1927                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][6]),
   1928                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][7]),
   1929                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][8]),
   1930                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][9])
   1931                             )
   1932                         ),
   1933                         ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   1934                             array(
   1935                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][0]),
   1936                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][1]),
   1937                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][2]),
   1938                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][3]),
   1939                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][4]),
   1940                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][5]),
   1941                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][6]),
   1942                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][7]),
   1943                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][8]),
   1944                                 ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][9])
   1945                             )
   1946                         )
   1947                     );
   1948                 }
   1949             }
   1950         }
   1951         if (!is_int($pos)) {
   1952             throw new InvalidArgumentException('Position must be an integer');
   1953         }
   1954         if ($pos < 0 || $pos > 31) {
   1955             throw new RangeException('Position is out of range [0, 31]');
   1956         }
   1957 
   1958         $bnegative = self::negative($b);
   1959         /** @var int $babs */
   1960         $babs = $b - (((-$bnegative) & $b) << 1);
   1961 
   1962         $t = self::ge_precomp_0();
   1963         for ($i = 0; $i < 8; ++$i) {
   1964             $t = self::cmov(
   1965                 $t,
   1966                 $base[$pos][$i],
   1967                 self::equal($babs, $i + 1)
   1968             );
   1969         }
   1970         $minusT = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
   1971             self::fe_copy($t->yminusx),
   1972             self::fe_copy($t->yplusx),
   1973             self::fe_neg($t->xy2d)
   1974         );
   1975         return self::cmov($t, $minusT, -$bnegative);
   1976     }
   1977 
   1978     /**
   1979      * Subtract two group elements.
   1980      *
   1981      * r = p - q
   1982      *
   1983      * @internal You should not use this directly from another application
   1984      *
   1985      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
   1986      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
   1987      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
   1988      * @throws SodiumException
   1989      * @throws TypeError
   1990      */
   1991     public static function ge_sub(
   1992         ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
   1993         ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
   1994     ) {
   1995         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
   1996 
   1997         $r->X = self::fe_add($p->Y, $p->X);
   1998         $r->Y = self::fe_sub($p->Y, $p->X);
   1999         $r->Z = self::fe_mul($r->X, $q->YminusX);
   2000         $r->Y = self::fe_mul($r->Y, $q->YplusX);
   2001         $r->T = self::fe_mul($q->T2d, $p->T);
   2002         $r->X = self::fe_mul($p->Z, $q->Z);
   2003         $t0 = self::fe_add($r->X, $r->X);
   2004         $r->X = self::fe_sub($r->Z, $r->Y);
   2005         $r->Y = self::fe_add($r->Z, $r->Y);
   2006         $r->Z = self::fe_sub($t0, $r->T);
   2007         $r->T = self::fe_add($t0, $r->T);
   2008 
   2009         return $r;
   2010     }
   2011 
   2012     /**
   2013      * Convert a group element to a byte string.
   2014      *
   2015      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h
   2016      * @return string
   2017      * @throws SodiumException
   2018      * @throws TypeError
   2019      */
   2020     public static function ge_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h)
   2021     {
   2022         $recip = self::fe_invert($h->Z);
   2023         $x = self::fe_mul($h->X, $recip);
   2024         $y = self::fe_mul($h->Y, $recip);
   2025         $s = self::fe_tobytes($y);
   2026         $s[31] = self::intToChr(
   2027             self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
   2028         );
   2029         return $s;
   2030     }
   2031 
   2032     /**
   2033      * @internal You should not use this directly from another application
   2034      *
   2035      * @param string $a
   2036      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A
   2037      * @param string $b
   2038      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
   2039      * @throws SodiumException
   2040      * @throws TypeError
   2041      * @psalm-suppress MixedArrayAccess
   2042      */
   2043     public static function ge_double_scalarmult_vartime(
   2044         $a,
   2045         ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A,
   2046         $b
   2047     ) {
   2048         /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */
   2049         $Ai = array();
   2050 
   2051         static $Bi = array();
   2052         /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */
   2053         if (!$Bi) {
   2054             for ($i = 0; $i < 8; ++$i) {
   2055                 $Bi[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
   2056                     ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   2057                         array(
   2058                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][0]),
   2059                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][1]),
   2060                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][2]),
   2061                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][3]),
   2062                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][4]),
   2063                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][5]),
   2064                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][6]),
   2065                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][7]),
   2066                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][8]),
   2067                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][9])
   2068                         )
   2069                     ),
   2070                     ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   2071                         array(
   2072                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][0]),
   2073                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][1]),
   2074                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][2]),
   2075                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][3]),
   2076                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][4]),
   2077                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][5]),
   2078                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][6]),
   2079                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][7]),
   2080                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][8]),
   2081                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][9])
   2082                         )
   2083                     ),
   2084                     ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
   2085                         array(
   2086                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][0]),
   2087                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][1]),
   2088                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][2]),
   2089                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][3]),
   2090                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][4]),
   2091                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][5]),
   2092                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][6]),
   2093                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][7]),
   2094                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][8]),
   2095                             ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][9])
   2096                         )
   2097                     )
   2098                 );
   2099             }
   2100         }
   2101 
   2102         for ($i = 0; $i < 8; ++$i) {
   2103             $Ai[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached(
   2104                 self::fe_0(),
   2105                 self::fe_0(),
   2106                 self::fe_0(),
   2107                 self::fe_0()
   2108             );
   2109         }
   2110         /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */
   2111 
   2112         # slide(aslide,a);
   2113         # slide(bslide,b);
   2114         /** @var array<int, int> $aslide */
   2115         $aslide = self::slide($a);
   2116         /** @var array<int, int> $bslide */
   2117         $bslide = self::slide($b);
   2118 
   2119         # ge_p3_to_cached(&Ai[0],A);
   2120         # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
   2121         $Ai[0] = self::ge_p3_to_cached($A);
   2122         $t = self::ge_p3_dbl($A);
   2123         $A2 = self::ge_p1p1_to_p3($t);
   2124 
   2125         # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
   2126         # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
   2127         # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
   2128         # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
   2129         # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
   2130         # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
   2131         # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
   2132         for ($i = 0; $i < 7; ++$i) {
   2133             $t = self::ge_add($A2, $Ai[$i]);
   2134             $u = self::ge_p1p1_to_p3($t);
   2135             $Ai[$i + 1] = self::ge_p3_to_cached($u);
   2136         }
   2137 
   2138         # ge_p2_0(r);
   2139         $r = self::ge_p2_0();
   2140 
   2141         # for (i = 255;i >= 0;--i) {
   2142         #     if (aslide[i] || bslide[i]) break;
   2143         # }
   2144         $i = 255;
   2145         for (; $i >= 0; --$i) {
   2146             if ($aslide[$i] || $bslide[$i]) {
   2147                 break;
   2148             }
   2149         }
   2150 
   2151         # for (;i >= 0;--i) {
   2152         for (; $i >= 0; --$i) {
   2153             # ge_p2_dbl(&t,r);
   2154             $t = self::ge_p2_dbl($r);
   2155 
   2156             # if (aslide[i] > 0) {
   2157             if ($aslide[$i] > 0) {
   2158                 # ge_p1p1_to_p3(&u,&t);
   2159                 # ge_add(&t,&u,&Ai[aslide[i]/2]);
   2160                 $u = self::ge_p1p1_to_p3($t);
   2161                 $t = self::ge_add(
   2162                     $u,
   2163                     $Ai[(int) floor($aslide[$i] / 2)]
   2164                 );
   2165                 # } else if (aslide[i] < 0) {
   2166             } elseif ($aslide[$i] < 0) {
   2167                 # ge_p1p1_to_p3(&u,&t);
   2168                 # ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
   2169                 $u = self::ge_p1p1_to_p3($t);
   2170                 $t = self::ge_sub(
   2171                     $u,
   2172                     $Ai[(int) floor(-$aslide[$i] / 2)]
   2173                 );
   2174             }
   2175             /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */
   2176 
   2177             # if (bslide[i] > 0) {
   2178             if ($bslide[$i] > 0) {
   2179                 # ge_p1p1_to_p3(&u,&t);
   2180                 # ge_madd(&t,&u,&Bi[bslide[i]/2]);
   2181                 $u = self::ge_p1p1_to_p3($t);
   2182                 /** @var int $index */
   2183                 $index = (int) floor($bslide[$i] / 2);
   2184                 /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $thisB */
   2185                 $thisB = $Bi[$index];
   2186                 $t = self::ge_madd($t, $u, $thisB);
   2187                 # } else if (bslide[i] < 0) {
   2188             } elseif ($bslide[$i] < 0) {
   2189                 # ge_p1p1_to_p3(&u,&t);
   2190                 # ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
   2191                 $u = self::ge_p1p1_to_p3($t);
   2192 
   2193                 /** @var int $index */
   2194                 $index = (int) floor(-$bslide[$i] / 2);
   2195 
   2196                 /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $thisB */
   2197                 $thisB = $Bi[$index];
   2198                 $t = self::ge_msub($t, $u, $thisB);
   2199             }
   2200             # ge_p1p1_to_p2(r,&t);
   2201             $r = self::ge_p1p1_to_p2($t);
   2202         }
   2203         return $r;
   2204     }
   2205 
   2206     /**
   2207      * @internal You should not use this directly from another application
   2208      *
   2209      * @param string $a
   2210      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
   2211      * @psalm-suppress MixedAssignment
   2212      * @psalm-suppress MixedOperand
   2213      * @throws SodiumException
   2214      * @throws TypeError
   2215      */
   2216     public static function ge_scalarmult_base($a)
   2217     {
   2218         /** @var array<int, int> $e */
   2219         $e = array();
   2220         $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
   2221 
   2222         for ($i = 0; $i < 32; ++$i) {
   2223             /** @var int $dbl */
   2224             $dbl = (int) $i << 1;
   2225             $e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
   2226             $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
   2227         }
   2228 
   2229         /** @var int $carry */
   2230         $carry = 0;
   2231         for ($i = 0; $i < 63; ++$i) {
   2232             $e[$i] += $carry;
   2233             /** @var int $carry */
   2234             $carry = $e[$i] + 8;
   2235             /** @var int $carry */
   2236             $carry >>= 4;
   2237             $e[$i] -= $carry << 4;
   2238         }
   2239 
   2240         /** @var array<int, int> $e */
   2241         $e[63] += (int) $carry;
   2242 
   2243         $h = self::ge_p3_0();
   2244 
   2245         for ($i = 1; $i < 64; $i += 2) {
   2246             $t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
   2247             $r = self::ge_madd($r, $h, $t);
   2248             $h = self::ge_p1p1_to_p3($r);
   2249         }
   2250 
   2251         $r = self::ge_p3_dbl($h);
   2252 
   2253         $s = self::ge_p1p1_to_p2($r);
   2254         $r = self::ge_p2_dbl($s);
   2255         $s = self::ge_p1p1_to_p2($r);
   2256         $r = self::ge_p2_dbl($s);
   2257         $s = self::ge_p1p1_to_p2($r);
   2258         $r = self::ge_p2_dbl($s);
   2259 
   2260         $h = self::ge_p1p1_to_p3($r);
   2261 
   2262         for ($i = 0; $i < 64; $i += 2) {
   2263             $t = self::ge_select($i >> 1, (int) $e[$i]);
   2264             $r = self::ge_madd($r, $h, $t);
   2265             $h = self::ge_p1p1_to_p3($r);
   2266         }
   2267         return $h;
   2268     }
   2269 
   2270     /**
   2271      * Calculates (ab + c) mod l
   2272      * where l = 2^252 + 27742317777372353535851937790883648493
   2273      *
   2274      * @internal You should not use this directly from another application
   2275      *
   2276      * @param string $a
   2277      * @param string $b
   2278      * @param string $c
   2279      * @return string
   2280      * @throws SodiumException
   2281      * @throws TypeError
   2282      */
   2283     public static function sc_muladd($a, $b, $c)
   2284     {
   2285         $a0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($a, 0, 3)));
   2286         $a1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5));
   2287         $a2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2));
   2288         $a3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7));
   2289         $a4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4));
   2290         $a5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1));
   2291         $a6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6));
   2292         $a7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3));
   2293         $a8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($a, 21, 3)));
   2294         $a9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5));
   2295         $a10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2));
   2296         $a11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($a, 28, 4)) >> 7));
   2297         $b0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($b, 0, 3)));
   2298         $b1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5));
   2299         $b2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2));
   2300         $b3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7));
   2301         $b4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4));
   2302         $b5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1));
   2303         $b6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6));
   2304         $b7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3));
   2305         $b8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($b, 21, 3)));
   2306         $b9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5));
   2307         $b10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2));
   2308         $b11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($b, 28, 4)) >> 7));
   2309         $c0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($c, 0, 3)));
   2310         $c1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5));
   2311         $c2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2));
   2312         $c3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7));
   2313         $c4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4));
   2314         $c5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1));
   2315         $c6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6));
   2316         $c7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3));
   2317         $c8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($c, 21, 3)));
   2318         $c9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5));
   2319         $c10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2));
   2320         $c11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($c, 28, 4)) >> 7));
   2321 
   2322         /* Can't really avoid the pyramid here: */
   2323         /**
   2324          * @var ParagonIE_Sodium_Core32_Int64 $s0
   2325          * @var ParagonIE_Sodium_Core32_Int64 $s1
   2326          * @var ParagonIE_Sodium_Core32_Int64 $s2
   2327          * @var ParagonIE_Sodium_Core32_Int64 $s3
   2328          * @var ParagonIE_Sodium_Core32_Int64 $s4
   2329          * @var ParagonIE_Sodium_Core32_Int64 $s5
   2330          * @var ParagonIE_Sodium_Core32_Int64 $s6
   2331          * @var ParagonIE_Sodium_Core32_Int64 $s7
   2332          * @var ParagonIE_Sodium_Core32_Int64 $s8
   2333          * @var ParagonIE_Sodium_Core32_Int64 $s9
   2334          * @var ParagonIE_Sodium_Core32_Int64 $s10
   2335          * @var ParagonIE_Sodium_Core32_Int64 $s11
   2336          * @var ParagonIE_Sodium_Core32_Int64 $s12
   2337          * @var ParagonIE_Sodium_Core32_Int64 $s13
   2338          * @var ParagonIE_Sodium_Core32_Int64 $s14
   2339          * @var ParagonIE_Sodium_Core32_Int64 $s15
   2340          * @var ParagonIE_Sodium_Core32_Int64 $s16
   2341          * @var ParagonIE_Sodium_Core32_Int64 $s17
   2342          * @var ParagonIE_Sodium_Core32_Int64 $s18
   2343          * @var ParagonIE_Sodium_Core32_Int64 $s19
   2344          * @var ParagonIE_Sodium_Core32_Int64 $s20
   2345          * @var ParagonIE_Sodium_Core32_Int64 $s21
   2346          * @var ParagonIE_Sodium_Core32_Int64 $s22
   2347          * @var ParagonIE_Sodium_Core32_Int64 $s23
   2348          */
   2349 
   2350         $s0 = $c0->addInt64($a0->mulInt64($b0, 24));
   2351         $s1 = $c1->addInt64($a0->mulInt64($b1, 24))->addInt64($a1->mulInt64($b0, 24));
   2352         $s2 = $c2->addInt64($a0->mulInt64($b2, 24))->addInt64($a1->mulInt64($b1, 24))->addInt64($a2->mulInt64($b0, 24));
   2353         $s3 = $c3->addInt64($a0->mulInt64($b3, 24))->addInt64($a1->mulInt64($b2, 24))->addInt64($a2->mulInt64($b1, 24))
   2354                  ->addInt64($a3->mulInt64($b0, 24));
   2355         $s4 = $c4->addInt64($a0->mulInt64($b4, 24))->addInt64($a1->mulInt64($b3, 24))->addInt64($a2->mulInt64($b2, 24))
   2356                  ->addInt64($a3->mulInt64($b1, 24))->addInt64($a4->mulInt64($b0, 24));
   2357         $s5 = $c5->addInt64($a0->mulInt64($b5, 24))->addInt64($a1->mulInt64($b4, 24))->addInt64($a2->mulInt64($b3, 24))
   2358                  ->addInt64($a3->mulInt64($b2, 24))->addInt64($a4->mulInt64($b1, 24))->addInt64($a5->mulInt64($b0, 24));
   2359         $s6 = $c6->addInt64($a0->mulInt64($b6, 24))->addInt64($a1->mulInt64($b5, 24))->addInt64($a2->mulInt64($b4, 24))
   2360                  ->addInt64($a3->mulInt64($b3, 24))->addInt64($a4->mulInt64($b2, 24))->addInt64($a5->mulInt64($b1, 24))
   2361                  ->addInt64($a6->mulInt64($b0, 24));
   2362         $s7 = $c7->addInt64($a0->mulInt64($b7, 24))->addInt64($a1->mulInt64($b6, 24))->addInt64($a2->mulInt64($b5, 24))
   2363                  ->addInt64($a3->mulInt64($b4, 24))->addInt64($a4->mulInt64($b3, 24))->addInt64($a5->mulInt64($b2, 24))
   2364                  ->addInt64($a6->mulInt64($b1, 24))->addInt64($a7->mulInt64($b0, 24));
   2365         $s8 = $c8->addInt64($a0->mulInt64($b8, 24))->addInt64($a1->mulInt64($b7, 24))->addInt64($a2->mulInt64($b6, 24))
   2366                  ->addInt64($a3->mulInt64($b5, 24))->addInt64($a4->mulInt64($b4, 24))->addInt64($a5->mulInt64($b3, 24))
   2367                  ->addInt64($a6->mulInt64($b2, 24))->addInt64($a7->mulInt64($b1, 24))->addInt64($a8->mulInt64($b0, 24));
   2368         $s9 = $c9->addInt64($a0->mulInt64($b9, 24))->addInt64($a1->mulInt64($b8, 24))->addInt64($a2->mulInt64($b7, 24))
   2369                  ->addInt64($a3->mulInt64($b6, 24))->addInt64($a4->mulInt64($b5, 24))->addInt64($a5->mulInt64($b4, 24))
   2370                  ->addInt64($a6->mulInt64($b3, 24))->addInt64($a7->mulInt64($b2, 24))->addInt64($a8->mulInt64($b1, 24))
   2371                  ->addInt64($a9->mulInt64($b0, 24));
   2372         $s10 = $c10->addInt64($a0->mulInt64($b10, 24))->addInt64($a1->mulInt64($b9, 24))->addInt64($a2->mulInt64($b8, 24))
   2373                    ->addInt64($a3->mulInt64($b7, 24))->addInt64($a4->mulInt64($b6, 24))->addInt64($a5->mulInt64($b5, 24))
   2374                    ->addInt64($a6->mulInt64($b4, 24))->addInt64($a7->mulInt64($b3, 24))->addInt64($a8->mulInt64($b2, 24))
   2375                    ->addInt64($a9->mulInt64($b1, 24))->addInt64($a10->mulInt64($b0, 24));
   2376         $s11 = $c11->addInt64($a0->mulInt64($b11, 24))->addInt64($a1->mulInt64($b10, 24))->addInt64($a2->mulInt64($b9, 24))
   2377                    ->addInt64($a3->mulInt64($b8, 24))->addInt64($a4->mulInt64($b7, 24))->addInt64($a5->mulInt64($b6, 24))
   2378                    ->addInt64($a6->mulInt64($b5, 24))->addInt64($a7->mulInt64($b4, 24))->addInt64($a8->mulInt64($b3, 24))
   2379                    ->addInt64($a9->mulInt64($b2, 24))->addInt64($a10->mulInt64($b1, 24))->addInt64($a11->mulInt64($b0, 24));
   2380         $s12 = $a1->mulInt64($b11, 24)->addInt64($a2->mulInt64($b10, 24))->addInt64($a3->mulInt64($b9, 24))
   2381                   ->addInt64($a4->mulInt64($b8, 24))->addInt64($a5->mulInt64($b7, 24))->addInt64($a6->mulInt64($b6, 24))
   2382                   ->addInt64($a7->mulInt64($b5, 24))->addInt64($a8->mulInt64($b4, 24))->addInt64($a9->mulInt64($b3, 24))
   2383                   ->addInt64($a10->mulInt64($b2, 24))->addInt64($a11->mulInt64($b1, 24));
   2384         $s13 = $a2->mulInt64($b11, 24)->addInt64($a3->mulInt64($b10, 24))->addInt64($a4->mulInt64($b9, 24))
   2385                   ->addInt64($a5->mulInt64($b8, 24))->addInt64($a6->mulInt64($b7, 24))->addInt64($a7->mulInt64($b6, 24))
   2386                   ->addInt64($a8->mulInt64($b5, 24))->addInt64($a9->mulInt64($b4, 24))->addInt64($a10->mulInt64($b3, 24))
   2387                   ->addInt64($a11->mulInt64($b2, 24));
   2388         $s14 = $a3->mulInt64($b11, 24)->addInt64($a4->mulInt64($b10, 24))->addInt64($a5->mulInt64($b9, 24))
   2389                   ->addInt64($a6->mulInt64($b8, 24))->addInt64($a7->mulInt64($b7, 24))->addInt64($a8->mulInt64($b6, 24))
   2390                   ->addInt64($a9->mulInt64($b5, 24))->addInt64($a10->mulInt64($b4, 24))->addInt64($a11->mulInt64($b3, 24));
   2391         $s15 = $a4->mulInt64($b11, 24)->addInt64($a5->mulInt64($b10, 24))->addInt64($a6->mulInt64($b9, 24))
   2392                   ->addInt64($a7->mulInt64($b8, 24))->addInt64($a8->mulInt64($b7, 24))->addInt64($a9->mulInt64($b6, 24))
   2393                   ->addInt64($a10->mulInt64($b5, 24))->addInt64($a11->mulInt64($b4, 24));
   2394         $s16 = $a5->mulInt64($b11, 24)->addInt64($a6->mulInt64($b10, 24))->addInt64($a7->mulInt64($b9, 24))
   2395                   ->addInt64($a8->mulInt64($b8, 24))->addInt64($a9->mulInt64($b7, 24))->addInt64($a10->mulInt64($b6, 24))
   2396                   ->addInt64($a11->mulInt64($b5, 24));
   2397         $s17 = $a6->mulInt64($b11, 24)->addInt64($a7->mulInt64($b10, 24))->addInt64($a8->mulInt64($b9, 24))
   2398                   ->addInt64($a9->mulInt64($b8, 24))->addInt64($a10->mulInt64($b7, 24))->addInt64($a11->mulInt64($b6, 24));
   2399         $s18 = $a7->mulInt64($b11, 24)->addInt64($a8->mulInt64($b10, 24))->addInt64($a9->mulInt64($b9, 24))
   2400                   ->addInt64($a10->mulInt64($b8, 24))->addInt64($a11->mulInt64($b7, 24));
   2401         $s19 = $a8->mulInt64($b11, 24)->addInt64($a9->mulInt64($b10, 24))->addInt64($a10->mulInt64($b9, 24))
   2402                   ->addInt64($a11->mulInt64($b8, 24));
   2403         $s20 = $a9->mulInt64($b11, 24)->addInt64($a10->mulInt64($b10, 24))->addInt64($a11->mulInt64($b9, 24));
   2404         $s21 = $a10->mulInt64($b11, 24)->addInt64($a11->mulInt64($b10, 24));
   2405         $s22 = $a11->mulInt64($b11, 24);
   2406         $s23 = new ParagonIE_Sodium_Core32_Int64();
   2407 
   2408         $carry0 = $s0->addInt(1 << 20)->shiftRight(21);
   2409         $s1 = $s1->addInt64($carry0);
   2410         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   2411         $carry2 = $s2->addInt(1 << 20)->shiftRight(21);
   2412         $s3 = $s3->addInt64($carry2);
   2413         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   2414         $carry4 = $s4->addInt(1 << 20)->shiftRight(21);
   2415         $s5 = $s5->addInt64($carry4);
   2416         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   2417         $carry6 = $s6->addInt(1 << 20)->shiftRight(21);
   2418         $s7 = $s7->addInt64($carry6);
   2419         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2420         $carry8 = $s8->addInt(1 << 20)->shiftRight(21);
   2421         $s9 = $s9->addInt64($carry8);
   2422         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2423         $carry10 = $s10->addInt(1 << 20)->shiftRight(21);
   2424         $s11 = $s11->addInt64($carry10);
   2425         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2426         $carry12 = $s12->addInt(1 << 20)->shiftRight(21);
   2427         $s13 = $s13->addInt64($carry12);
   2428         $s12 = $s12->subInt64($carry12->shiftLeft(21));
   2429         $carry14 = $s14->addInt(1 << 20)->shiftRight(21);
   2430         $s15 = $s15->addInt64($carry14);
   2431         $s14 = $s14->subInt64($carry14->shiftLeft(21));
   2432         $carry16 = $s16->addInt(1 << 20)->shiftRight(21);
   2433         $s17 = $s17->addInt64($carry16);
   2434         $s16 = $s16->subInt64($carry16->shiftLeft(21));
   2435         $carry18 = $s18->addInt(1 << 20)->shiftRight(21);
   2436         $s19 = $s19->addInt64($carry18);
   2437         $s18 = $s18->subInt64($carry18->shiftLeft(21));
   2438         $carry20 = $s20->addInt(1 << 20)->shiftRight(21);
   2439         $s21 = $s21->addInt64($carry20);
   2440         $s20 = $s20->subInt64($carry20->shiftLeft(21));
   2441         $carry22 = $s22->addInt(1 << 20)->shiftRight(21);
   2442         $s23 = $s23->addInt64($carry22);
   2443         $s22 = $s22->subInt64($carry22->shiftLeft(21));
   2444 
   2445         $carry1 = $s1->addInt(1 << 20)->shiftRight(21);
   2446         $s2 = $s2->addInt64($carry1);
   2447         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   2448         $carry3 = $s3->addInt(1 << 20)->shiftRight(21);
   2449         $s4 = $s4->addInt64($carry3);
   2450         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   2451         $carry5 = $s5->addInt(1 << 20)->shiftRight(21);
   2452         $s6 = $s6->addInt64($carry5);
   2453         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   2454         $carry7 = $s7->addInt(1 << 20)->shiftRight(21);
   2455         $s8 = $s8->addInt64($carry7);
   2456         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2457         $carry9 = $s9->addInt(1 << 20)->shiftRight(21);
   2458         $s10 = $s10->addInt64($carry9);
   2459         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2460         $carry11 = $s11->addInt(1 << 20)->shiftRight(21);
   2461         $s12 = $s12->addInt64($carry11);
   2462         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   2463         $carry13 = $s13->addInt(1 << 20)->shiftRight(21);
   2464         $s14 = $s14->addInt64($carry13);
   2465         $s13 = $s13->subInt64($carry13->shiftLeft(21));
   2466         $carry15 = $s15->addInt(1 << 20)->shiftRight(21);
   2467         $s16 = $s16->addInt64($carry15);
   2468         $s15 = $s15->subInt64($carry15->shiftLeft(21));
   2469         $carry17 = $s17->addInt(1 << 20)->shiftRight(21);
   2470         $s18 = $s18->addInt64($carry17);
   2471         $s17 = $s17->subInt64($carry17->shiftLeft(21));
   2472         $carry19 = $s19->addInt(1 << 20)->shiftRight(21);
   2473         $s20 = $s20->addInt64($carry19);
   2474         $s19 = $s19->subInt64($carry19->shiftLeft(21));
   2475         $carry21 = $s21->addInt(1 << 20)->shiftRight(21);
   2476         $s22 = $s22->addInt64($carry21);
   2477         $s21 = $s21->subInt64($carry21->shiftLeft(21));
   2478 
   2479         $s11 = $s11->addInt64($s23->mulInt(666643, 20));
   2480         $s12 = $s12->addInt64($s23->mulInt(470296, 19));
   2481         $s13 = $s13->addInt64($s23->mulInt(654183, 20));
   2482         $s14 = $s14->subInt64($s23->mulInt(997805, 20));
   2483         $s15 = $s15->addInt64($s23->mulInt(136657, 18));
   2484         $s16 = $s16->subInt64($s23->mulInt(683901, 20));
   2485 
   2486         $s10 = $s10->addInt64($s22->mulInt(666643, 20));
   2487         $s11 = $s11->addInt64($s22->mulInt(470296, 19));
   2488         $s12 = $s12->addInt64($s22->mulInt(654183, 20));
   2489         $s13 = $s13->subInt64($s22->mulInt(997805, 20));
   2490         $s14 = $s14->addInt64($s22->mulInt(136657, 18));
   2491         $s15 = $s15->subInt64($s22->mulInt(683901, 20));
   2492 
   2493         $s9  =  $s9->addInt64($s21->mulInt(666643, 20));
   2494         $s10 = $s10->addInt64($s21->mulInt(470296, 19));
   2495         $s11 = $s11->addInt64($s21->mulInt(654183, 20));
   2496         $s12 = $s12->subInt64($s21->mulInt(997805, 20));
   2497         $s13 = $s13->addInt64($s21->mulInt(136657, 18));
   2498         $s14 = $s14->subInt64($s21->mulInt(683901, 20));
   2499 
   2500         $s8  =  $s8->addInt64($s20->mulInt(666643, 20));
   2501         $s9  =  $s9->addInt64($s20->mulInt(470296, 19));
   2502         $s10 = $s10->addInt64($s20->mulInt(654183, 20));
   2503         $s11 = $s11->subInt64($s20->mulInt(997805, 20));
   2504         $s12 = $s12->addInt64($s20->mulInt(136657, 18));
   2505         $s13 = $s13->subInt64($s20->mulInt(683901, 20));
   2506 
   2507         $s7  =  $s7->addInt64($s19->mulInt(666643, 20));
   2508         $s8  =  $s8->addInt64($s19->mulInt(470296, 19));
   2509         $s9  =  $s9->addInt64($s19->mulInt(654183, 20));
   2510         $s10 = $s10->subInt64($s19->mulInt(997805, 20));
   2511         $s11 = $s11->addInt64($s19->mulInt(136657, 18));
   2512         $s12 = $s12->subInt64($s19->mulInt(683901, 20));
   2513 
   2514         $s6  =  $s6->addInt64($s18->mulInt(666643, 20));
   2515         $s7  =  $s7->addInt64($s18->mulInt(470296, 19));
   2516         $s8  =  $s8->addInt64($s18->mulInt(654183, 20));
   2517         $s9  =  $s9->subInt64($s18->mulInt(997805, 20));
   2518         $s10 = $s10->addInt64($s18->mulInt(136657, 18));
   2519         $s11 = $s11->subInt64($s18->mulInt(683901, 20));
   2520 
   2521         $carry6 = $s6->addInt(1 << 20)->shiftRight(21);
   2522         $s7 = $s7->addInt64($carry6);
   2523         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2524         $carry8 = $s8->addInt(1 << 20)->shiftRight(21);
   2525         $s9 = $s9->addInt64($carry8);
   2526         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2527         $carry10 = $s10->addInt(1 << 20)->shiftRight(21);
   2528         $s11 = $s11->addInt64($carry10);
   2529         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2530         $carry12 = $s12->addInt(1 << 20)->shiftRight(21);
   2531         $s13 = $s13->addInt64($carry12);
   2532         $s12 = $s12->subInt64($carry12->shiftLeft(21));
   2533         $carry14 = $s14->addInt(1 << 20)->shiftRight(21);
   2534         $s15 = $s15->addInt64($carry14);
   2535         $s14 = $s14->subInt64($carry14->shiftLeft(21));
   2536         $carry16 = $s16->addInt(1 << 20)->shiftRight(21);
   2537         $s17 = $s17->addInt64($carry16);
   2538         $s16 = $s16->subInt64($carry16->shiftLeft(21));
   2539 
   2540         $carry7 = $s7->addInt(1 << 20)->shiftRight(21);
   2541         $s8 = $s8->addInt64($carry7);
   2542         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2543         $carry9 = $s9->addInt(1 << 20)->shiftRight(21);
   2544         $s10 = $s10->addInt64($carry9);
   2545         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2546         $carry11 = $s11->addInt(1 << 20)->shiftRight(21);
   2547         $s12 = $s12->addInt64($carry11);
   2548         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   2549         $carry13 = $s13->addInt(1 << 20)->shiftRight(21);
   2550         $s14 = $s14->addInt64($carry13);
   2551         $s13 = $s13->subInt64($carry13->shiftLeft(21));
   2552         $carry15 = $s15->addInt(1 << 20)->shiftRight(21);
   2553         $s16 = $s16->addInt64($carry15);
   2554         $s15 = $s15->subInt64($carry15->shiftLeft(21));
   2555 
   2556         $s5  =  $s5->addInt64($s17->mulInt(666643, 20));
   2557         $s6  =  $s6->addInt64($s17->mulInt(470296, 19));
   2558         $s7  =  $s7->addInt64($s17->mulInt(654183, 20));
   2559         $s8  =  $s8->subInt64($s17->mulInt(997805, 20));
   2560         $s9  =  $s9->addInt64($s17->mulInt(136657, 18));
   2561         $s10 = $s10->subInt64($s17->mulInt(683901, 20));
   2562 
   2563         $s4  =  $s4->addInt64($s16->mulInt(666643, 20));
   2564         $s5  =  $s5->addInt64($s16->mulInt(470296, 19));
   2565         $s6  =  $s6->addInt64($s16->mulInt(654183, 20));
   2566         $s7  =  $s7->subInt64($s16->mulInt(997805, 20));
   2567         $s8  =  $s8->addInt64($s16->mulInt(136657, 18));
   2568         $s9  =  $s9->subInt64($s16->mulInt(683901, 20));
   2569 
   2570         $s3  =  $s3->addInt64($s15->mulInt(666643, 20));
   2571         $s4  =  $s4->addInt64($s15->mulInt(470296, 19));
   2572         $s5  =  $s5->addInt64($s15->mulInt(654183, 20));
   2573         $s6  =  $s6->subInt64($s15->mulInt(997805, 20));
   2574         $s7  =  $s7->addInt64($s15->mulInt(136657, 18));
   2575         $s8  =  $s8->subInt64($s15->mulInt(683901, 20));
   2576 
   2577         $s2  =  $s2->addInt64($s14->mulInt(666643, 20));
   2578         $s3  =  $s3->addInt64($s14->mulInt(470296, 19));
   2579         $s4  =  $s4->addInt64($s14->mulInt(654183, 20));
   2580         $s5  =  $s5->subInt64($s14->mulInt(997805, 20));
   2581         $s6  =  $s6->addInt64($s14->mulInt(136657, 18));
   2582         $s7  =  $s7->subInt64($s14->mulInt(683901, 20));
   2583 
   2584         $s1  =  $s1->addInt64($s13->mulInt(666643, 20));
   2585         $s2  =  $s2->addInt64($s13->mulInt(470296, 19));
   2586         $s3  =  $s3->addInt64($s13->mulInt(654183, 20));
   2587         $s4  =  $s4->subInt64($s13->mulInt(997805, 20));
   2588         $s5  =  $s5->addInt64($s13->mulInt(136657, 18));
   2589         $s6  =  $s6->subInt64($s13->mulInt(683901, 20));
   2590 
   2591         $s0  =  $s0->addInt64($s12->mulInt(666643, 20));
   2592         $s1  =  $s1->addInt64($s12->mulInt(470296, 19));
   2593         $s2  =  $s2->addInt64($s12->mulInt(654183, 20));
   2594         $s3  =  $s3->subInt64($s12->mulInt(997805, 20));
   2595         $s4  =  $s4->addInt64($s12->mulInt(136657, 18));
   2596         $s5  =  $s5->subInt64($s12->mulInt(683901, 20));
   2597         $s12 = new ParagonIE_Sodium_Core32_Int64();
   2598 
   2599         $carry0 = $s0->addInt(1 << 20)->shiftRight(21);
   2600         $s1 = $s1->addInt64($carry0);
   2601         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   2602         $carry2 = $s2->addInt(1 << 20)->shiftRight(21);
   2603         $s3 = $s3->addInt64($carry2);
   2604         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   2605         $carry4 = $s4->addInt(1 << 20)->shiftRight(21);
   2606         $s5 = $s5->addInt64($carry4);
   2607         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   2608         $carry6 = $s6->addInt(1 << 20)->shiftRight(21);
   2609         $s7 = $s7->addInt64($carry6);
   2610         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2611         $carry8 = $s8->addInt(1 << 20)->shiftRight(21);
   2612         $s9 = $s9->addInt64($carry8);
   2613         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2614         $carry10 = $s10->addInt(1 << 20)->shiftRight(21);
   2615         $s11 = $s11->addInt64($carry10);
   2616         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2617 
   2618         $carry1 = $s1->addInt(1 << 20)->shiftRight(21);
   2619         $s2 = $s2->addInt64($carry1);
   2620         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   2621         $carry3 = $s3->addInt(1 << 20)->shiftRight(21);
   2622         $s4 = $s4->addInt64($carry3);
   2623         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   2624         $carry5 = $s5->addInt(1 << 20)->shiftRight(21);
   2625         $s6 = $s6->addInt64($carry5);
   2626         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   2627         $carry7 = $s7->addInt(1 << 20)->shiftRight(21);
   2628         $s8 = $s8->addInt64($carry7);
   2629         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2630         $carry9 = $s9->addInt(1 << 20)->shiftRight(21);
   2631         $s10 = $s10->addInt64($carry9);
   2632         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2633         $carry11 = $s11->addInt(1 << 20)->shiftRight(21);
   2634         $s12 = $s12->addInt64($carry11);
   2635         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   2636 
   2637         $s0  =  $s0->addInt64($s12->mulInt(666643, 20));
   2638         $s1  =  $s1->addInt64($s12->mulInt(470296, 19));
   2639         $s2  =  $s2->addInt64($s12->mulInt(654183, 20));
   2640         $s3  =  $s3->subInt64($s12->mulInt(997805, 20));
   2641         $s4  =  $s4->addInt64($s12->mulInt(136657, 18));
   2642         $s5  =  $s5->subInt64($s12->mulInt(683901, 20));
   2643         $s12 = new ParagonIE_Sodium_Core32_Int64();
   2644 
   2645         $carry0 = $s0->shiftRight(21);
   2646         $s1 = $s1->addInt64($carry0);
   2647         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   2648         $carry1 = $s1->shiftRight(21);
   2649         $s2 = $s2->addInt64($carry1);
   2650         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   2651         $carry2 = $s2->shiftRight(21);
   2652         $s3 = $s3->addInt64($carry2);
   2653         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   2654         $carry3 = $s3->shiftRight(21);
   2655         $s4 = $s4->addInt64($carry3);
   2656         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   2657         $carry4 = $s4->shiftRight(21);
   2658         $s5 = $s5->addInt64($carry4);
   2659         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   2660         $carry5 = $s5->shiftRight(21);
   2661         $s6 = $s6->addInt64($carry5);
   2662         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   2663         $carry6 = $s6->shiftRight(21);
   2664         $s7 = $s7->addInt64($carry6);
   2665         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2666         $carry7 = $s7->shiftRight(21);
   2667         $s8 = $s8->addInt64($carry7);
   2668         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2669         $carry8 = $s8->shiftRight(21);
   2670         $s9 = $s9->addInt64($carry8);
   2671         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2672         $carry9 = $s9->shiftRight(21);
   2673         $s10 = $s10->addInt64($carry9);
   2674         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2675         $carry10 = $s10->shiftRight(21);
   2676         $s11 = $s11->addInt64($carry10);
   2677         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2678         $carry11 = $s11->shiftRight(21);
   2679         $s12 = $s12->addInt64($carry11);
   2680         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   2681 
   2682         $s0  =  $s0->addInt64($s12->mulInt(666643, 20));
   2683         $s1  =  $s1->addInt64($s12->mulInt(470296, 19));
   2684         $s2  =  $s2->addInt64($s12->mulInt(654183, 20));
   2685         $s3  =  $s3->subInt64($s12->mulInt(997805, 20));
   2686         $s4  =  $s4->addInt64($s12->mulInt(136657, 18));
   2687         $s5  =  $s5->subInt64($s12->mulInt(683901, 20));
   2688 
   2689         $carry0 = $s0->shiftRight(21);
   2690         $s1 = $s1->addInt64($carry0);
   2691         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   2692         $carry1 = $s1->shiftRight(21);
   2693         $s2 = $s2->addInt64($carry1);
   2694         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   2695         $carry2 = $s2->shiftRight(21);
   2696         $s3 = $s3->addInt64($carry2);
   2697         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   2698         $carry3 = $s3->shiftRight(21);
   2699         $s4 = $s4->addInt64($carry3);
   2700         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   2701         $carry4 = $s4->shiftRight(21);
   2702         $s5 = $s5->addInt64($carry4);
   2703         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   2704         $carry5 = $s5->shiftRight(21);
   2705         $s6 = $s6->addInt64($carry5);
   2706         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   2707         $carry6 = $s6->shiftRight(21);
   2708         $s7 = $s7->addInt64($carry6);
   2709         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2710         $carry7 = $s7->shiftRight(21);
   2711         $s8 = $s8->addInt64($carry7);
   2712         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2713         $carry8 = $s10->shiftRight(21);
   2714         $s9 = $s9->addInt64($carry8);
   2715         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2716         $carry9 = $s9->shiftRight(21);
   2717         $s10 = $s10->addInt64($carry9);
   2718         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2719         $carry10 = $s10->shiftRight(21);
   2720         $s11 = $s11->addInt64($carry10);
   2721         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2722 
   2723         $S0  =  $s0->toInt();
   2724         $S1  =  $s1->toInt();
   2725         $S2  =  $s2->toInt();
   2726         $S3  =  $s3->toInt();
   2727         $S4  =  $s4->toInt();
   2728         $S5  =  $s5->toInt();
   2729         $S6  =  $s6->toInt();
   2730         $S7  =  $s7->toInt();
   2731         $S8  =  $s8->toInt();
   2732         $S9  =  $s9->toInt();
   2733         $S10 = $s10->toInt();
   2734         $S11 = $s11->toInt();
   2735 
   2736         /**
   2737          * @var array<int, int>
   2738          */
   2739         $arr = array(
   2740             (int) (0xff & ($S0 >> 0)),
   2741             (int) (0xff & ($S0 >> 8)),
   2742             (int) (0xff & (($S0 >> 16) | ($S1 << 5))),
   2743             (int) (0xff & ($S1 >> 3)),
   2744             (int) (0xff & ($S1 >> 11)),
   2745             (int) (0xff & (($S1 >> 19) | ($S2 << 2))),
   2746             (int) (0xff & ($S2 >> 6)),
   2747             (int) (0xff & (($S2 >> 14) | ($S3 << 7))),
   2748             (int) (0xff & ($S3 >> 1)),
   2749             (int) (0xff & ($S3 >> 9)),
   2750             (int) (0xff & (($S3 >> 17) | ($S4 << 4))),
   2751             (int) (0xff & ($S4 >> 4)),
   2752             (int) (0xff & ($S4 >> 12)),
   2753             (int) (0xff & (($S4 >> 20) | ($S5 << 1))),
   2754             (int) (0xff & ($S5 >> 7)),
   2755             (int) (0xff & (($S5 >> 15) | ($S6 << 6))),
   2756             (int) (0xff & ($S6 >> 2)),
   2757             (int) (0xff & ($S6 >> 10)),
   2758             (int) (0xff & (($S6 >> 18) | ($S7 << 3))),
   2759             (int) (0xff & ($S7 >> 5)),
   2760             (int) (0xff & ($S7 >> 13)),
   2761             (int) (0xff & ($S8 >> 0)),
   2762             (int) (0xff & ($S8 >> 8)),
   2763             (int) (0xff & (($S8 >> 16) | ($S9 << 5))),
   2764             (int) (0xff & ($S9 >> 3)),
   2765             (int) (0xff & ($S9 >> 11)),
   2766             (int) (0xff & (($S9 >> 19) | ($S10 << 2))),
   2767             (int) (0xff & ($S10 >> 6)),
   2768             (int) (0xff & (($S10 >> 14) | ($S11 << 7))),
   2769             (int) (0xff & ($S11 >> 1)),
   2770             (int) (0xff & ($S11 >> 9)),
   2771             (int) (0xff & ($S11 >> 17))
   2772         );
   2773         return self::intArrayToString($arr);
   2774     }
   2775 
   2776     /**
   2777      * @internal You should not use this directly from another application
   2778      *
   2779      * @param string $s
   2780      * @return string
   2781      * @throws SodiumException
   2782      * @throws TypeError
   2783      */
   2784     public static function sc_reduce($s)
   2785     {
   2786         /**
   2787          * @var ParagonIE_Sodium_Core32_Int64 $s0
   2788          * @var ParagonIE_Sodium_Core32_Int64 $s1
   2789          * @var ParagonIE_Sodium_Core32_Int64 $s2
   2790          * @var ParagonIE_Sodium_Core32_Int64 $s3
   2791          * @var ParagonIE_Sodium_Core32_Int64 $s4
   2792          * @var ParagonIE_Sodium_Core32_Int64 $s5
   2793          * @var ParagonIE_Sodium_Core32_Int64 $s6
   2794          * @var ParagonIE_Sodium_Core32_Int64 $s7
   2795          * @var ParagonIE_Sodium_Core32_Int64 $s8
   2796          * @var ParagonIE_Sodium_Core32_Int64 $s9
   2797          * @var ParagonIE_Sodium_Core32_Int64 $s10
   2798          * @var ParagonIE_Sodium_Core32_Int64 $s11
   2799          * @var ParagonIE_Sodium_Core32_Int64 $s12
   2800          * @var ParagonIE_Sodium_Core32_Int64 $s13
   2801          * @var ParagonIE_Sodium_Core32_Int64 $s14
   2802          * @var ParagonIE_Sodium_Core32_Int64 $s15
   2803          * @var ParagonIE_Sodium_Core32_Int64 $s16
   2804          * @var ParagonIE_Sodium_Core32_Int64 $s17
   2805          * @var ParagonIE_Sodium_Core32_Int64 $s18
   2806          * @var ParagonIE_Sodium_Core32_Int64 $s19
   2807          * @var ParagonIE_Sodium_Core32_Int64 $s20
   2808          * @var ParagonIE_Sodium_Core32_Int64 $s21
   2809          * @var ParagonIE_Sodium_Core32_Int64 $s22
   2810          * @var ParagonIE_Sodium_Core32_Int64 $s23
   2811          */
   2812         $s0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 0, 3)));
   2813         $s1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5));
   2814         $s2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2));
   2815         $s3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7));
   2816         $s4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4));
   2817         $s5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1));
   2818         $s6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6));
   2819         $s7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3));
   2820         $s8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 21, 3)));
   2821         $s9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5));
   2822         $s10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2));
   2823         $s11 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7));
   2824         $s12 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4));
   2825         $s13 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1));
   2826         $s14 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6));
   2827         $s15 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3));
   2828         $s16 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 42, 3)));
   2829         $s17 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5));
   2830         $s18 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2));
   2831         $s19 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7));
   2832         $s20 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4));
   2833         $s21 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1));
   2834         $s22 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6));
   2835         $s23 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3));
   2836 
   2837         $s11 = $s11->addInt64($s23->mulInt(666643, 20));
   2838         $s12 = $s12->addInt64($s23->mulInt(470296, 19));
   2839         $s13 = $s13->addInt64($s23->mulInt(654183, 20));
   2840         $s14 = $s14->subInt64($s23->mulInt(997805, 20));
   2841         $s15 = $s15->addInt64($s23->mulInt(136657, 18));
   2842         $s16 = $s16->subInt64($s23->mulInt(683901, 20));
   2843 
   2844         $s10 = $s10->addInt64($s22->mulInt(666643, 20));
   2845         $s11 = $s11->addInt64($s22->mulInt(470296, 19));
   2846         $s12 = $s12->addInt64($s22->mulInt(654183, 20));
   2847         $s13 = $s13->subInt64($s22->mulInt(997805, 20));
   2848         $s14 = $s14->addInt64($s22->mulInt(136657, 18));
   2849         $s15 = $s15->subInt64($s22->mulInt(683901, 20));
   2850 
   2851         $s9  =  $s9->addInt64($s21->mulInt(666643, 20));
   2852         $s10 = $s10->addInt64($s21->mulInt(470296, 19));
   2853         $s11 = $s11->addInt64($s21->mulInt(654183, 20));
   2854         $s12 = $s12->subInt64($s21->mulInt(997805, 20));
   2855         $s13 = $s13->addInt64($s21->mulInt(136657, 18));
   2856         $s14 = $s14->subInt64($s21->mulInt(683901, 20));
   2857 
   2858         $s8  =  $s8->addInt64($s20->mulInt(666643, 20));
   2859         $s9  =  $s9->addInt64($s20->mulInt(470296, 19));
   2860         $s10 = $s10->addInt64($s20->mulInt(654183, 20));
   2861         $s11 = $s11->subInt64($s20->mulInt(997805, 20));
   2862         $s12 = $s12->addInt64($s20->mulInt(136657, 18));
   2863         $s13 = $s13->subInt64($s20->mulInt(683901, 20));
   2864 
   2865         $s7  =  $s7->addInt64($s19->mulInt(666643, 20));
   2866         $s8  =  $s8->addInt64($s19->mulInt(470296, 19));
   2867         $s9  =  $s9->addInt64($s19->mulInt(654183, 20));
   2868         $s10 = $s10->subInt64($s19->mulInt(997805, 20));
   2869         $s11 = $s11->addInt64($s19->mulInt(136657, 18));
   2870         $s12 = $s12->subInt64($s19->mulInt(683901, 20));
   2871 
   2872         $s6  =  $s6->addInt64($s18->mulInt(666643, 20));
   2873         $s7  =  $s7->addInt64($s18->mulInt(470296, 19));
   2874         $s8  =  $s8->addInt64($s18->mulInt(654183, 20));
   2875         $s9  =  $s9->subInt64($s18->mulInt(997805, 20));
   2876         $s10 = $s10->addInt64($s18->mulInt(136657, 18));
   2877         $s11 = $s11->subInt64($s18->mulInt(683901, 20));
   2878 
   2879         $carry6 = $s6->addInt(1 << 20)->shiftRight(21);
   2880         $s7 = $s7->addInt64($carry6);
   2881         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2882         $carry8 = $s8->addInt(1 << 20)->shiftRight(21);
   2883         $s9 = $s9->addInt64($carry8);
   2884         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2885         $carry10 = $s10->addInt(1 << 20)->shiftRight(21);
   2886         $s11 = $s11->addInt64($carry10);
   2887         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2888         $carry12 = $s12->addInt(1 << 20)->shiftRight(21);
   2889         $s13 = $s13->addInt64($carry12);
   2890         $s12 = $s12->subInt64($carry12->shiftLeft(21));
   2891         $carry14 = $s14->addInt(1 << 20)->shiftRight(21);
   2892         $s15 = $s15->addInt64($carry14);
   2893         $s14 = $s14->subInt64($carry14->shiftLeft(21));
   2894         $carry16 = $s16->addInt(1 << 20)->shiftRight(21);
   2895         $s17 = $s17->addInt64($carry16);
   2896         $s16 = $s16->subInt64($carry16->shiftLeft(21));
   2897 
   2898         $carry7 = $s7->addInt(1 << 20)->shiftRight(21);
   2899         $s8 = $s8->addInt64($carry7);
   2900         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2901         $carry9 = $s9->addInt(1 << 20)->shiftRight(21);
   2902         $s10 = $s10->addInt64($carry9);
   2903         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2904         $carry11 = $s11->addInt(1 << 20)->shiftRight(21);
   2905         $s12 = $s12->addInt64($carry11);
   2906         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   2907         $carry13 = $s13->addInt(1 << 20)->shiftRight(21);
   2908         $s14 = $s14->addInt64($carry13);
   2909         $s13 = $s13->subInt64($carry13->shiftLeft(21));
   2910         $carry15 = $s15->addInt(1 << 20)->shiftRight(21);
   2911         $s16 = $s16->addInt64($carry15);
   2912         $s15 = $s15->subInt64($carry15->shiftLeft(21));
   2913 
   2914         $s5  =  $s5->addInt64($s17->mulInt(666643, 20));
   2915         $s6  =  $s6->addInt64($s17->mulInt(470296, 19));
   2916         $s7  =  $s7->addInt64($s17->mulInt(654183, 20));
   2917         $s8  =  $s8->subInt64($s17->mulInt(997805, 20));
   2918         $s9  =  $s9->addInt64($s17->mulInt(136657, 18));
   2919         $s10 = $s10->subInt64($s17->mulInt(683901, 20));
   2920 
   2921         $s4  =  $s4->addInt64($s16->mulInt(666643, 20));
   2922         $s5  =  $s5->addInt64($s16->mulInt(470296, 19));
   2923         $s6  =  $s6->addInt64($s16->mulInt(654183, 20));
   2924         $s7  =  $s7->subInt64($s16->mulInt(997805, 20));
   2925         $s8  =  $s8->addInt64($s16->mulInt(136657, 18));
   2926         $s9  =  $s9->subInt64($s16->mulInt(683901, 20));
   2927 
   2928         $s3  =  $s3->addInt64($s15->mulInt(666643, 20));
   2929         $s4  =  $s4->addInt64($s15->mulInt(470296, 19));
   2930         $s5  =  $s5->addInt64($s15->mulInt(654183, 20));
   2931         $s6  =  $s6->subInt64($s15->mulInt(997805, 20));
   2932         $s7  =  $s7->addInt64($s15->mulInt(136657, 18));
   2933         $s8  =  $s8->subInt64($s15->mulInt(683901, 20));
   2934 
   2935         $s2  =  $s2->addInt64($s14->mulInt(666643, 20));
   2936         $s3  =  $s3->addInt64($s14->mulInt(470296, 19));
   2937         $s4  =  $s4->addInt64($s14->mulInt(654183, 20));
   2938         $s5  =  $s5->subInt64($s14->mulInt(997805, 20));
   2939         $s6  =  $s6->addInt64($s14->mulInt(136657, 18));
   2940         $s7  =  $s7->subInt64($s14->mulInt(683901, 20));
   2941 
   2942         $s1  =  $s1->addInt64($s13->mulInt(666643, 20));
   2943         $s2  =  $s2->addInt64($s13->mulInt(470296, 19));
   2944         $s3  =  $s3->addInt64($s13->mulInt(654183, 20));
   2945         $s4  =  $s4->subInt64($s13->mulInt(997805, 20));
   2946         $s5  =  $s5->addInt64($s13->mulInt(136657, 18));
   2947         $s6  =  $s6->subInt64($s13->mulInt(683901, 20));
   2948 
   2949         $s0  =  $s0->addInt64($s12->mulInt(666643, 20));
   2950         $s1  =  $s1->addInt64($s12->mulInt(470296, 19));
   2951         $s2  =  $s2->addInt64($s12->mulInt(654183, 20));
   2952         $s3  =  $s3->subInt64($s12->mulInt(997805, 20));
   2953         $s4  =  $s4->addInt64($s12->mulInt(136657, 18));
   2954         $s5  =  $s5->subInt64($s12->mulInt(683901, 20));
   2955         $s12 = new ParagonIE_Sodium_Core32_Int64();
   2956 
   2957         $carry0 = $s0->addInt(1 << 20)->shiftRight(21);
   2958         $s1 = $s1->addInt64($carry0);
   2959         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   2960         $carry2 = $s2->addInt(1 << 20)->shiftRight(21);
   2961         $s3 = $s3->addInt64($carry2);
   2962         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   2963         $carry4 = $s4->addInt(1 << 20)->shiftRight(21);
   2964         $s5 = $s5->addInt64($carry4);
   2965         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   2966         $carry6 = $s6->addInt(1 << 20)->shiftRight(21);
   2967         $s7 = $s7->addInt64($carry6);
   2968         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   2969         $carry8 = $s8->addInt(1 << 20)->shiftRight(21);
   2970         $s9 = $s9->addInt64($carry8);
   2971         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   2972         $carry10 = $s10->addInt(1 << 20)->shiftRight(21);
   2973         $s11 = $s11->addInt64($carry10);
   2974         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   2975         $carry1 = $s1->addInt(1 << 20)->shiftRight(21);
   2976         $s2 = $s2->addInt64($carry1);
   2977         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   2978         $carry3 = $s3->addInt(1 << 20)->shiftRight(21);
   2979         $s4 = $s4->addInt64($carry3);
   2980         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   2981         $carry5 = $s5->addInt(1 << 20)->shiftRight(21);
   2982         $s6 = $s6->addInt64($carry5);
   2983         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   2984         $carry7 = $s7->addInt(1 << 20)->shiftRight(21);
   2985         $s8 = $s8->addInt64($carry7);
   2986         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   2987         $carry9 = $s9->addInt(1 << 20)->shiftRight(21);
   2988         $s10 = $s10->addInt64($carry9);
   2989         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   2990         $carry11 = $s11->addInt(1 << 20)->shiftRight(21);
   2991         $s12 = $s12->addInt64($carry11);
   2992         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   2993 
   2994         $s0  =  $s0->addInt64($s12->mulInt(666643, 20));
   2995         $s1  =  $s1->addInt64($s12->mulInt(470296, 19));
   2996         $s2  =  $s2->addInt64($s12->mulInt(654183, 20));
   2997         $s3  =  $s3->subInt64($s12->mulInt(997805, 20));
   2998         $s4  =  $s4->addInt64($s12->mulInt(136657, 18));
   2999         $s5  =  $s5->subInt64($s12->mulInt(683901, 20));
   3000         $s12 = new ParagonIE_Sodium_Core32_Int64();
   3001 
   3002         $carry0 = $s0->shiftRight(21);
   3003         $s1 = $s1->addInt64($carry0);
   3004         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   3005         $carry1 = $s1->shiftRight(21);
   3006         $s2 = $s2->addInt64($carry1);
   3007         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   3008         $carry2 = $s2->shiftRight(21);
   3009         $s3 = $s3->addInt64($carry2);
   3010         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   3011         $carry3 = $s3->shiftRight(21);
   3012         $s4 = $s4->addInt64($carry3);
   3013         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   3014         $carry4 = $s4->shiftRight(21);
   3015         $s5 = $s5->addInt64($carry4);
   3016         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   3017         $carry5 = $s5->shiftRight(21);
   3018         $s6 = $s6->addInt64($carry5);
   3019         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   3020         $carry6 = $s6->shiftRight(21);
   3021         $s7 = $s7->addInt64($carry6);
   3022         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   3023         $carry7 = $s7->shiftRight(21);
   3024         $s8 = $s8->addInt64($carry7);
   3025         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   3026         $carry8 = $s8->shiftRight(21);
   3027         $s9 = $s9->addInt64($carry8);
   3028         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   3029         $carry9 = $s9->shiftRight(21);
   3030         $s10 = $s10->addInt64($carry9);
   3031         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   3032         $carry10 = $s10->shiftRight(21);
   3033         $s11 = $s11->addInt64($carry10);
   3034         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   3035         $carry11 = $s11->shiftRight(21);
   3036         $s12 = $s12->addInt64($carry11);
   3037         $s11 = $s11->subInt64($carry11->shiftLeft(21));
   3038 
   3039         $s0  =  $s0->addInt64($s12->mulInt(666643, 20));
   3040         $s1  =  $s1->addInt64($s12->mulInt(470296, 19));
   3041         $s2  =  $s2->addInt64($s12->mulInt(654183, 20));
   3042         $s3  =  $s3->subInt64($s12->mulInt(997805, 20));
   3043         $s4  =  $s4->addInt64($s12->mulInt(136657, 18));
   3044         $s5  =  $s5->subInt64($s12->mulInt(683901, 20));
   3045 
   3046         $carry0 = $s0->shiftRight(21);
   3047         $s1 = $s1->addInt64($carry0);
   3048         $s0 = $s0->subInt64($carry0->shiftLeft(21));
   3049         $carry1 = $s1->shiftRight(21);
   3050         $s2 = $s2->addInt64($carry1);
   3051         $s1 = $s1->subInt64($carry1->shiftLeft(21));
   3052         $carry2 = $s2->shiftRight(21);
   3053         $s3 = $s3->addInt64($carry2);
   3054         $s2 = $s2->subInt64($carry2->shiftLeft(21));
   3055         $carry3 = $s3->shiftRight(21);
   3056         $s4 = $s4->addInt64($carry3);
   3057         $s3 = $s3->subInt64($carry3->shiftLeft(21));
   3058         $carry4 = $s4->shiftRight(21);
   3059         $s5 = $s5->addInt64($carry4);
   3060         $s4 = $s4->subInt64($carry4->shiftLeft(21));
   3061         $carry5 = $s5->shiftRight(21);
   3062         $s6 = $s6->addInt64($carry5);
   3063         $s5 = $s5->subInt64($carry5->shiftLeft(21));
   3064         $carry6 = $s6->shiftRight(21);
   3065         $s7 = $s7->addInt64($carry6);
   3066         $s6 = $s6->subInt64($carry6->shiftLeft(21));
   3067         $carry7 = $s7->shiftRight(21);
   3068         $s8 = $s8->addInt64($carry7);
   3069         $s7 = $s7->subInt64($carry7->shiftLeft(21));
   3070         $carry8 = $s8->shiftRight(21);
   3071         $s9 = $s9->addInt64($carry8);
   3072         $s8 = $s8->subInt64($carry8->shiftLeft(21));
   3073         $carry9 = $s9->shiftRight(21);
   3074         $s10 = $s10->addInt64($carry9);
   3075         $s9 = $s9->subInt64($carry9->shiftLeft(21));
   3076         $carry10 = $s10->shiftRight(21);
   3077         $s11 = $s11->addInt64($carry10);
   3078         $s10 = $s10->subInt64($carry10->shiftLeft(21));
   3079 
   3080         $S0 = $s0->toInt32()->toInt();
   3081         $S1 = $s1->toInt32()->toInt();
   3082         $S2 = $s2->toInt32()->toInt();
   3083         $S3 = $s3->toInt32()->toInt();
   3084         $S4 = $s4->toInt32()->toInt();
   3085         $S5 = $s5->toInt32()->toInt();
   3086         $S6 = $s6->toInt32()->toInt();
   3087         $S7 = $s7->toInt32()->toInt();
   3088         $S8 = $s8->toInt32()->toInt();
   3089         $S9 = $s9->toInt32()->toInt();
   3090         $S10 = $s10->toInt32()->toInt();
   3091         $S11 = $s11->toInt32()->toInt();
   3092 
   3093         /**
   3094          * @var array<int, int>
   3095          */
   3096         $arr = array(
   3097             (int) ($S0 >> 0),
   3098             (int) ($S0 >> 8),
   3099             (int) (($S0 >> 16) | ($S1 << 5)),
   3100             (int) ($S1 >> 3),
   3101             (int) ($S1 >> 11),
   3102             (int) (($S1 >> 19) | ($S2 << 2)),
   3103             (int) ($S2 >> 6),
   3104             (int) (($S2 >> 14) | ($S3 << 7)),
   3105             (int) ($S3 >> 1),
   3106             (int) ($S3 >> 9),
   3107             (int) (($S3 >> 17) | ($S4 << 4)),
   3108             (int) ($S4 >> 4),
   3109             (int) ($S4 >> 12),
   3110             (int) (($S4 >> 20) | ($S5 << 1)),
   3111             (int) ($S5 >> 7),
   3112             (int) (($S5 >> 15) | ($S6 << 6)),
   3113             (int) ($S6 >> 2),
   3114             (int) ($S6 >> 10),
   3115             (int) (($S6 >> 18) | ($S7 << 3)),
   3116             (int) ($S7 >> 5),
   3117             (int) ($S7 >> 13),
   3118             (int) ($S8 >> 0),
   3119             (int) ($S8 >> 8),
   3120             (int) (($S8 >> 16) | ($S9 << 5)),
   3121             (int) ($S9 >> 3),
   3122             (int) ($S9 >> 11),
   3123             (int) (($S9 >> 19) | ($S10 << 2)),
   3124             (int) ($S10 >> 6),
   3125             (int) (($S10 >> 14) | ($S11 << 7)),
   3126             (int) ($S11 >> 1),
   3127             (int) ($S11 >> 9),
   3128             (int) $S11 >> 17
   3129         );
   3130         return self::intArrayToString($arr);
   3131     }
   3132 
   3133     /**
   3134      * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
   3135      *
   3136      * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A
   3137      * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
   3138      * @throws SodiumException
   3139      * @throws TypeError
   3140      */
   3141     public static function ge_mul_l(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A)
   3142     {
   3143         /** @var array<int, int> $aslide */
   3144         $aslide = array(
   3145             13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
   3146             0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
   3147             0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
   3148             0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
   3149             0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
   3150             0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
   3151             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3152             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3153             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3154             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3155             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3156             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
   3157         );
   3158 
   3159         /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai size 8 */
   3160         $Ai = array();
   3161 
   3162         # ge_p3_to_cached(&Ai[0], A);
   3163         $Ai[0] = self::ge_p3_to_cached($A);
   3164         # ge_p3_dbl(&t, A);
   3165         $t = self::ge_p3_dbl($A);
   3166         # ge_p1p1_to_p3(&A2, &t);
   3167         $A2 = self::ge_p1p1_to_p3($t);
   3168 
   3169         for ($i = 1; $i < 8; ++$i) {
   3170             # ge_add(&t, &A2, &Ai[0]);
   3171             $t = self::ge_add($A2, $Ai[$i - 1]);
   3172             # ge_p1p1_to_p3(&u, &t);
   3173             $u = self::ge_p1p1_to_p3($t);
   3174             # ge_p3_to_cached(&Ai[i], &u);
   3175             $Ai[$i] = self::ge_p3_to_cached($u);
   3176         }
   3177 
   3178         $r = self::ge_p3_0();
   3179         for ($i = 252; $i >= 0; --$i) {
   3180             $t = self::ge_p3_dbl($r);
   3181             if ($aslide[$i] > 0) {
   3182                 # ge_p1p1_to_p3(&u, &t);
   3183                 $u = self::ge_p1p1_to_p3($t);
   3184                 # ge_add(&t, &u, &Ai[aslide[i] / 2]);
   3185                 $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
   3186             } elseif ($aslide[$i] < 0) {
   3187                 # ge_p1p1_to_p3(&u, &t);
   3188                 $u = self::ge_p1p1_to_p3($t);
   3189                 # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
   3190                 $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
   3191             }
   3192         }
   3193         # ge_p1p1_to_p3(r, &t);
   3194         return self::ge_p1p1_to_p3($t);
   3195     }
   3196 }