angelovcom.net

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

Curve25519.php (150637B)


      1 <?php
      2 
      3 if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
      4     return;
      5 }
      6 
      7 /**
      8  * Class ParagonIE_Sodium_Core_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_Core_Curve25519 extends ParagonIE_Sodium_Core_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_Core_Curve25519_Fe
     24      */
     25     public static function fe_0()
     26     {
     27         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
     28             array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
     29         );
     30     }
     31 
     32     /**
     33      * Get a field element of size 10 with a value of 1
     34      *
     35      * @internal You should not use this directly from another application
     36      *
     37      * @return ParagonIE_Sodium_Core_Curve25519_Fe
     38      */
     39     public static function fe_1()
     40     {
     41         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
     42             array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
     43         );
     44     }
     45 
     46     /**
     47      * Add two field elements.
     48      *
     49      * @internal You should not use this directly from another application
     50      *
     51      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     52      * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
     53      * @return ParagonIE_Sodium_Core_Curve25519_Fe
     54      * @psalm-suppress MixedAssignment
     55      * @psalm-suppress MixedOperand
     56      */
     57     public static function fe_add(
     58         ParagonIE_Sodium_Core_Curve25519_Fe $f,
     59         ParagonIE_Sodium_Core_Curve25519_Fe $g
     60     ) {
     61         /** @var array<int, int> $arr */
     62         $arr = array();
     63         for ($i = 0; $i < 10; ++$i) {
     64             $arr[$i] = (int) ($f[$i] + $g[$i]);
     65         }
     66         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr);
     67     }
     68 
     69     /**
     70      * Constant-time conditional move.
     71      *
     72      * @internal You should not use this directly from another application
     73      *
     74      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     75      * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
     76      * @param int $b
     77      * @return ParagonIE_Sodium_Core_Curve25519_Fe
     78      * @psalm-suppress MixedAssignment
     79      */
     80     public static function fe_cmov(
     81         ParagonIE_Sodium_Core_Curve25519_Fe $f,
     82         ParagonIE_Sodium_Core_Curve25519_Fe $g,
     83         $b = 0
     84     ) {
     85         /** @var array<int, int> $h */
     86         $h = array();
     87         $b *= -1;
     88         for ($i = 0; $i < 10; ++$i) {
     89             $x = (($f[$i] ^ $g[$i]) & $b);
     90             $h[$i] = ($f[$i]) ^ $x;
     91         }
     92         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
     93     }
     94 
     95     /**
     96      * Create a copy of a field element.
     97      *
     98      * @internal You should not use this directly from another application
     99      *
    100      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    101      * @return ParagonIE_Sodium_Core_Curve25519_Fe
    102      */
    103     public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    104     {
    105         $h = clone $f;
    106         return $h;
    107     }
    108 
    109     /**
    110      * Give: 32-byte string.
    111      * Receive: A field element object to use for internal calculations.
    112      *
    113      * @internal You should not use this directly from another application
    114      *
    115      * @param string $s
    116      * @return ParagonIE_Sodium_Core_Curve25519_Fe
    117      * @throws RangeException
    118      * @throws TypeError
    119      */
    120     public static function fe_frombytes($s)
    121     {
    122         if (self::strlen($s) !== 32) {
    123             throw new RangeException('Expected a 32-byte string.');
    124         }
    125         /** @var int $h0 */
    126         $h0 = self::load_4($s);
    127         /** @var int $h1 */
    128         $h1 = self::load_3(self::substr($s, 4, 3)) << 6;
    129         /** @var int $h2 */
    130         $h2 = self::load_3(self::substr($s, 7, 3)) << 5;
    131         /** @var int $h3 */
    132         $h3 = self::load_3(self::substr($s, 10, 3)) << 3;
    133         /** @var int $h4 */
    134         $h4 = self::load_3(self::substr($s, 13, 3)) << 2;
    135         /** @var int $h5 */
    136         $h5 = self::load_4(self::substr($s, 16, 4));
    137         /** @var int $h6 */
    138         $h6 = self::load_3(self::substr($s, 20, 3)) << 7;
    139         /** @var int $h7 */
    140         $h7 = self::load_3(self::substr($s, 23, 3)) << 5;
    141         /** @var int $h8 */
    142         $h8 = self::load_3(self::substr($s, 26, 3)) << 4;
    143         /** @var int $h9 */
    144         $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2;
    145 
    146         /** @var int $carry9 */
    147         $carry9 = ($h9 + (1 << 24)) >> 25;
    148         $h0 += self::mul($carry9, 19, 5);
    149         $h9 -= $carry9 << 25;
    150         /** @var int $carry1 */
    151         $carry1 = ($h1 + (1 << 24)) >> 25;
    152         $h2 += $carry1;
    153         $h1 -= $carry1 << 25;
    154         /** @var int $carry3 */
    155         $carry3 = ($h3 + (1 << 24)) >> 25;
    156         $h4 += $carry3;
    157         $h3 -= $carry3 << 25;
    158         /** @var int $carry5 */
    159         $carry5 = ($h5 + (1 << 24)) >> 25;
    160         $h6 += $carry5;
    161         $h5 -= $carry5 << 25;
    162         /** @var int $carry7 */
    163         $carry7 = ($h7 + (1 << 24)) >> 25;
    164         $h8 += $carry7;
    165         $h7 -= $carry7 << 25;
    166 
    167         /** @var int $carry0 */
    168         $carry0 = ($h0 + (1 << 25)) >> 26;
    169         $h1 += $carry0;
    170         $h0 -= $carry0 << 26;
    171         /** @var int $carry2 */
    172         $carry2 = ($h2 + (1 << 25)) >> 26;
    173         $h3 += $carry2;
    174         $h2 -= $carry2 << 26;
    175         /** @var int $carry4 */
    176         $carry4 = ($h4 + (1 << 25)) >> 26;
    177         $h5 += $carry4;
    178         $h4 -= $carry4 << 26;
    179         /** @var int $carry6 */
    180         $carry6 = ($h6 + (1 << 25)) >> 26;
    181         $h7 += $carry6;
    182         $h6 -= $carry6 << 26;
    183         /** @var int $carry8 */
    184         $carry8 = ($h8 + (1 << 25)) >> 26;
    185         $h9 += $carry8;
    186         $h8 -= $carry8 << 26;
    187 
    188         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
    189             array(
    190                 (int) $h0,
    191                 (int) $h1,
    192                 (int) $h2,
    193                 (int) $h3,
    194                 (int) $h4,
    195                 (int) $h5,
    196                 (int) $h6,
    197                 (int) $h7,
    198                 (int) $h8,
    199                 (int) $h9
    200             )
    201         );
    202     }
    203 
    204     /**
    205      * Convert a field element to a byte string.
    206      *
    207      * @internal You should not use this directly from another application
    208      *
    209      * @param ParagonIE_Sodium_Core_Curve25519_Fe $h
    210      * @return string
    211      */
    212     public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h)
    213     {
    214         /** @var int $h0 */
    215         $h0 = (int) $h[0];
    216         /** @var int $h1 */
    217         $h1 = (int) $h[1];
    218         /** @var int $h2 */
    219         $h2 = (int) $h[2];
    220         /** @var int $h3 */
    221         $h3 = (int) $h[3];
    222         /** @var int $h4 */
    223         $h4 = (int) $h[4];
    224         /** @var int $h5 */
    225         $h5 = (int) $h[5];
    226         /** @var int $h6 */
    227         $h6 = (int) $h[6];
    228         /** @var int $h7 */
    229         $h7 = (int) $h[7];
    230         /** @var int $h8 */
    231         $h8 = (int) $h[8];
    232         /** @var int $h9 */
    233         $h9 = (int) $h[9];
    234 
    235         /** @var int $q */
    236         $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
    237         /** @var int $q */
    238         $q = ($h0 + $q) >> 26;
    239         /** @var int $q */
    240         $q = ($h1 + $q) >> 25;
    241         /** @var int $q */
    242         $q = ($h2 + $q) >> 26;
    243         /** @var int $q */
    244         $q = ($h3 + $q) >> 25;
    245         /** @var int $q */
    246         $q = ($h4 + $q) >> 26;
    247         /** @var int $q */
    248         $q = ($h5 + $q) >> 25;
    249         /** @var int $q */
    250         $q = ($h6 + $q) >> 26;
    251         /** @var int $q */
    252         $q = ($h7 + $q) >> 25;
    253         /** @var int $q */
    254         $q = ($h8 + $q) >> 26;
    255         /** @var int $q */
    256         $q = ($h9 + $q) >> 25;
    257 
    258         $h0 += self::mul($q, 19, 5);
    259 
    260         /** @var int $carry0 */
    261         $carry0 = $h0 >> 26;
    262         $h1 += $carry0;
    263         $h0 -= $carry0 << 26;
    264         /** @var int $carry1 */
    265         $carry1 = $h1 >> 25;
    266         $h2 += $carry1;
    267         $h1 -= $carry1 << 25;
    268         /** @var int $carry2 */
    269         $carry2 = $h2 >> 26;
    270         $h3 += $carry2;
    271         $h2 -= $carry2 << 26;
    272         /** @var int $carry3 */
    273         $carry3 = $h3 >> 25;
    274         $h4 += $carry3;
    275         $h3 -= $carry3 << 25;
    276         /** @var int $carry4 */
    277         $carry4 = $h4 >> 26;
    278         $h5 += $carry4;
    279         $h4 -= $carry4 << 26;
    280         /** @var int $carry5 */
    281         $carry5 = $h5 >> 25;
    282         $h6 += $carry5;
    283         $h5 -= $carry5 << 25;
    284         /** @var int $carry6 */
    285         $carry6 = $h6 >> 26;
    286         $h7 += $carry6;
    287         $h6 -= $carry6 << 26;
    288         /** @var int $carry7 */
    289         $carry7 = $h7 >> 25;
    290         $h8 += $carry7;
    291         $h7 -= $carry7 << 25;
    292         /** @var int $carry8 */
    293         $carry8 = $h8 >> 26;
    294         $h9 += $carry8;
    295         $h8 -= $carry8 << 26;
    296         /** @var int $carry9 */
    297         $carry9 = $h9 >> 25;
    298         $h9 -= $carry9 << 25;
    299 
    300         /**
    301          * @var array<int, int>
    302          */
    303         $s = array(
    304             (int) (($h0 >> 0) & 0xff),
    305             (int) (($h0 >> 8) & 0xff),
    306             (int) (($h0 >> 16) & 0xff),
    307             (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
    308             (int) (($h1 >> 6) & 0xff),
    309             (int) (($h1 >> 14) & 0xff),
    310             (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
    311             (int) (($h2 >> 5) & 0xff),
    312             (int) (($h2 >> 13) & 0xff),
    313             (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
    314             (int) (($h3 >> 3) & 0xff),
    315             (int) (($h3 >> 11) & 0xff),
    316             (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
    317             (int) (($h4 >> 2) & 0xff),
    318             (int) (($h4 >> 10) & 0xff),
    319             (int) (($h4 >> 18) & 0xff),
    320             (int) (($h5 >> 0) & 0xff),
    321             (int) (($h5 >> 8) & 0xff),
    322             (int) (($h5 >> 16) & 0xff),
    323             (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
    324             (int) (($h6 >> 7) & 0xff),
    325             (int) (($h6 >> 15) & 0xff),
    326             (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
    327             (int) (($h7 >> 5) & 0xff),
    328             (int) (($h7 >> 13) & 0xff),
    329             (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
    330             (int) (($h8 >> 4) & 0xff),
    331             (int) (($h8 >> 12) & 0xff),
    332             (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
    333             (int) (($h9 >> 2) & 0xff),
    334             (int) (($h9 >> 10) & 0xff),
    335             (int) (($h9 >> 18) & 0xff)
    336         );
    337         return self::intArrayToString($s);
    338     }
    339 
    340     /**
    341      * Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
    342      *
    343      * @internal You should not use this directly from another application
    344      *
    345      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    346      * @return int
    347      * @throws SodiumException
    348      * @throws TypeError
    349      */
    350     public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    351     {
    352         $str = self::fe_tobytes($f);
    353         return (int) (self::chrToInt($str[0]) & 1);
    354     }
    355 
    356     /**
    357      * Returns 0 if this field element results in all NUL bytes.
    358      *
    359      * @internal You should not use this directly from another application
    360      *
    361      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    362      * @return bool
    363      * @throws SodiumException
    364      * @throws TypeError
    365      */
    366     public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    367     {
    368         static $zero;
    369         if ($zero === null) {
    370             $zero = str_repeat("\x00", 32);
    371         }
    372         /** @var string $zero */
    373         /** @var string $str */
    374         $str = self::fe_tobytes($f);
    375         return !self::verify_32($str, (string) $zero);
    376     }
    377 
    378     /**
    379      * Multiply two field elements
    380      *
    381      * h = f * g
    382      *
    383      * @internal You should not use this directly from another application
    384      *
    385      * @security Is multiplication a source of timing leaks? If so, can we do
    386      *           anything to prevent that from happening?
    387      *
    388      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    389      * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
    390      * @return ParagonIE_Sodium_Core_Curve25519_Fe
    391      */
    392     public static function fe_mul(
    393         ParagonIE_Sodium_Core_Curve25519_Fe $f,
    394         ParagonIE_Sodium_Core_Curve25519_Fe $g
    395     ) {
    396         /** @var int $f0 */
    397         $f0 = $f[0];
    398         /** @var int $f1 */
    399         $f1 = $f[1];
    400         /** @var int $f2 */
    401         $f2 = $f[2];
    402         /** @var int $f3 */
    403         $f3 = $f[3];
    404         /** @var int $f4 */
    405         $f4 = $f[4];
    406         /** @var int $f5 */
    407         $f5 = $f[5];
    408         /** @var int $f6 */
    409         $f6 = $f[6];
    410         /** @var int $f7 */
    411         $f7 = $f[7];
    412         /** @var int $f8 */
    413         $f8 = $f[8];
    414         /** @var int $f9 */
    415         $f9 = $f[9];
    416         /** @var int $g0 */
    417         $g0 = $g[0];
    418         /** @var int $g1 */
    419         $g1 = $g[1];
    420         /** @var int $g2 */
    421         $g2 = $g[2];
    422         /** @var int $g3 */
    423         $g3 = $g[3];
    424         /** @var int $g4 */
    425         $g4 = $g[4];
    426         /** @var int $g5 */
    427         $g5 = $g[5];
    428         /** @var int $g6 */
    429         $g6 = $g[6];
    430         /** @var int $g7 */
    431         $g7 = $g[7];
    432         /** @var int $g8 */
    433         $g8 = $g[8];
    434         /** @var int $g9 */
    435         $g9 = $g[9];
    436         $g1_19 = self::mul($g1, 19, 5);
    437         $g2_19 = self::mul($g2, 19, 5);
    438         $g3_19 = self::mul($g3, 19, 5);
    439         $g4_19 = self::mul($g4, 19, 5);
    440         $g5_19 = self::mul($g5, 19, 5);
    441         $g6_19 = self::mul($g6, 19, 5);
    442         $g7_19 = self::mul($g7, 19, 5);
    443         $g8_19 = self::mul($g8, 19, 5);
    444         $g9_19 = self::mul($g9, 19, 5);
    445         /** @var int $f1_2 */
    446         $f1_2 = $f1 << 1;
    447         /** @var int $f3_2 */
    448         $f3_2 = $f3 << 1;
    449         /** @var int $f5_2 */
    450         $f5_2 = $f5 << 1;
    451         /** @var int $f7_2 */
    452         $f7_2 = $f7 << 1;
    453         /** @var int $f9_2 */
    454         $f9_2 = $f9 << 1;
    455         $f0g0    = self::mul($f0,    $g0, 26);
    456         $f0g1    = self::mul($f0,    $g1, 25);
    457         $f0g2    = self::mul($f0,    $g2, 26);
    458         $f0g3    = self::mul($f0,    $g3, 25);
    459         $f0g4    = self::mul($f0,    $g4, 26);
    460         $f0g5    = self::mul($f0,    $g5, 25);
    461         $f0g6    = self::mul($f0,    $g6, 26);
    462         $f0g7    = self::mul($f0,    $g7, 25);
    463         $f0g8    = self::mul($f0,    $g8, 26);
    464         $f0g9    = self::mul($f0,    $g9, 26);
    465         $f1g0    = self::mul($f1,    $g0, 26);
    466         $f1g1_2  = self::mul($f1_2,  $g1, 25);
    467         $f1g2    = self::mul($f1,    $g2, 26);
    468         $f1g3_2  = self::mul($f1_2,  $g3, 25);
    469         $f1g4    = self::mul($f1,    $g4, 26);
    470         $f1g5_2  = self::mul($f1_2,  $g5, 25);
    471         $f1g6    = self::mul($f1,    $g6, 26);
    472         $f1g7_2  = self::mul($f1_2,  $g7, 25);
    473         $f1g8    = self::mul($f1,    $g8, 26);
    474         $f1g9_38 = self::mul($g9_19, $f1_2, 26);
    475         $f2g0    = self::mul($f2,    $g0, 26);
    476         $f2g1    = self::mul($f2,    $g1, 25);
    477         $f2g2    = self::mul($f2,    $g2, 26);
    478         $f2g3    = self::mul($f2,    $g3, 25);
    479         $f2g4    = self::mul($f2,    $g4, 26);
    480         $f2g5    = self::mul($f2,    $g5, 25);
    481         $f2g6    = self::mul($f2,    $g6, 26);
    482         $f2g7    = self::mul($f2,    $g7, 25);
    483         $f2g8_19 = self::mul($g8_19, $f2, 26);
    484         $f2g9_19 = self::mul($g9_19, $f2, 26);
    485         $f3g0    = self::mul($f3,    $g0, 26);
    486         $f3g1_2  = self::mul($f3_2,  $g1, 25);
    487         $f3g2    = self::mul($f3,    $g2, 26);
    488         $f3g3_2  = self::mul($f3_2,  $g3, 25);
    489         $f3g4    = self::mul($f3,    $g4, 26);
    490         $f3g5_2  = self::mul($f3_2,  $g5, 25);
    491         $f3g6    = self::mul($f3,    $g6, 26);
    492         $f3g7_38 = self::mul($g7_19, $f3_2, 26);
    493         $f3g8_19 = self::mul($g8_19, $f3, 25);
    494         $f3g9_38 = self::mul($g9_19, $f3_2, 26);
    495         $f4g0    = self::mul($f4,    $g0, 26);
    496         $f4g1    = self::mul($f4,    $g1, 25);
    497         $f4g2    = self::mul($f4,    $g2, 26);
    498         $f4g3    = self::mul($f4,    $g3, 25);
    499         $f4g4    = self::mul($f4,    $g4, 26);
    500         $f4g5    = self::mul($f4,    $g5, 25);
    501         $f4g6_19 = self::mul($g6_19, $f4, 26);
    502         $f4g7_19 = self::mul($g7_19, $f4, 26);
    503         $f4g8_19 = self::mul($g8_19, $f4, 26);
    504         $f4g9_19 = self::mul($g9_19, $f4, 26);
    505         $f5g0    = self::mul($f5,    $g0, 26);
    506         $f5g1_2  = self::mul($f5_2,  $g1, 25);
    507         $f5g2    = self::mul($f5,    $g2, 26);
    508         $f5g3_2  = self::mul($f5_2,  $g3, 25);
    509         $f5g4    = self::mul($f5,    $g4, 26);
    510         $f5g5_38 = self::mul($g5_19, $f5_2, 26);
    511         $f5g6_19 = self::mul($g6_19, $f5, 25);
    512         $f5g7_38 = self::mul($g7_19, $f5_2, 26);
    513         $f5g8_19 = self::mul($g8_19, $f5, 25);
    514         $f5g9_38 = self::mul($g9_19, $f5_2, 26);
    515         $f6g0    = self::mul($f6,    $g0, 26);
    516         $f6g1    = self::mul($f6,    $g1, 25);
    517         $f6g2    = self::mul($f6,    $g2, 26);
    518         $f6g3    = self::mul($f6,    $g3, 25);
    519         $f6g4_19 = self::mul($g4_19, $f6, 26);
    520         $f6g5_19 = self::mul($g5_19, $f6, 26);
    521         $f6g6_19 = self::mul($g6_19, $f6, 26);
    522         $f6g7_19 = self::mul($g7_19, $f6, 26);
    523         $f6g8_19 = self::mul($g8_19, $f6, 26);
    524         $f6g9_19 = self::mul($g9_19, $f6, 26);
    525         $f7g0    = self::mul($f7,    $g0, 26);
    526         $f7g1_2  = self::mul($f7_2,  $g1, 25);
    527         $f7g2    = self::mul($f7,    $g2, 26);
    528         $f7g3_38 = self::mul($g3_19, $f7_2, 26);
    529         $f7g4_19 = self::mul($g4_19, $f7, 26);
    530         $f7g5_38 = self::mul($g5_19, $f7_2, 26);
    531         $f7g6_19 = self::mul($g6_19, $f7, 25);
    532         $f7g7_38 = self::mul($g7_19, $f7_2, 26);
    533         $f7g8_19 = self::mul($g8_19, $f7, 25);
    534         $f7g9_38 = self::mul($g9_19,$f7_2, 26);
    535         $f8g0    = self::mul($f8,    $g0, 26);
    536         $f8g1    = self::mul($f8,    $g1, 25);
    537         $f8g2_19 = self::mul($g2_19, $f8, 26);
    538         $f8g3_19 = self::mul($g3_19, $f8, 26);
    539         $f8g4_19 = self::mul($g4_19, $f8, 26);
    540         $f8g5_19 = self::mul($g5_19, $f8, 26);
    541         $f8g6_19 = self::mul($g6_19, $f8, 26);
    542         $f8g7_19 = self::mul($g7_19, $f8, 26);
    543         $f8g8_19 = self::mul($g8_19, $f8, 26);
    544         $f8g9_19 = self::mul($g9_19, $f8, 26);
    545         $f9g0    = self::mul($f9,    $g0, 26);
    546         $f9g1_38 = self::mul($g1_19, $f9_2, 26);
    547         $f9g2_19 = self::mul($g2_19, $f9, 25);
    548         $f9g3_38 = self::mul($g3_19, $f9_2, 26);
    549         $f9g4_19 = self::mul($g4_19, $f9, 25);
    550         $f9g5_38 = self::mul($g5_19, $f9_2, 26);
    551         $f9g6_19 = self::mul($g6_19, $f9, 25);
    552         $f9g7_38 = self::mul($g7_19, $f9_2, 26);
    553         $f9g8_19 = self::mul($g8_19, $f9, 25);
    554         $f9g9_38 = self::mul($g9_19, $f9_2, 26);
    555         $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
    556         $h1 = $f0g1 + $f1g0    + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
    557         $h2 = $f0g2 + $f1g1_2  + $f2g0    + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
    558         $h3 = $f0g3 + $f1g2    + $f2g1    + $f3g0    + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
    559         $h4 = $f0g4 + $f1g3_2  + $f2g2    + $f3g1_2  + $f4g0    + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
    560         $h5 = $f0g5 + $f1g4    + $f2g3    + $f3g2    + $f4g1    + $f5g0    + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
    561         $h6 = $f0g6 + $f1g5_2  + $f2g4    + $f3g3_2  + $f4g2    + $f5g1_2  + $f6g0    + $f7g9_38 + $f8g8_19 + $f9g7_38;
    562         $h7 = $f0g7 + $f1g6    + $f2g5    + $f3g4    + $f4g3    + $f5g2    + $f6g1    + $f7g0    + $f8g9_19 + $f9g8_19;
    563         $h8 = $f0g8 + $f1g7_2  + $f2g6    + $f3g5_2  + $f4g4    + $f5g3_2  + $f6g2    + $f7g1_2  + $f8g0    + $f9g9_38;
    564         $h9 = $f0g9 + $f1g8    + $f2g7    + $f3g6    + $f4g5    + $f5g4    + $f6g3    + $f7g2    + $f8g1    + $f9g0   ;
    565 
    566         /** @var int $carry0 */
    567         $carry0 = ($h0 + (1 << 25)) >> 26;
    568         $h1 += $carry0;
    569         $h0 -= $carry0 << 26;
    570         /** @var int $carry4 */
    571         $carry4 = ($h4 + (1 << 25)) >> 26;
    572         $h5 += $carry4;
    573         $h4 -= $carry4 << 26;
    574 
    575         /** @var int $carry1 */
    576         $carry1 = ($h1 + (1 << 24)) >> 25;
    577         $h2 += $carry1;
    578         $h1 -= $carry1 << 25;
    579         /** @var int $carry5 */
    580         $carry5 = ($h5 + (1 << 24)) >> 25;
    581         $h6 += $carry5;
    582         $h5 -= $carry5 << 25;
    583 
    584         /** @var int $carry2 */
    585         $carry2 = ($h2 + (1 << 25)) >> 26;
    586         $h3 += $carry2;
    587         $h2 -= $carry2 << 26;
    588         /** @var int $carry6 */
    589         $carry6 = ($h6 + (1 << 25)) >> 26;
    590         $h7 += $carry6;
    591         $h6 -= $carry6 << 26;
    592 
    593         /** @var int $carry3 */
    594         $carry3 = ($h3 + (1 << 24)) >> 25;
    595         $h4 += $carry3;
    596         $h3 -= $carry3 << 25;
    597         /** @var int $carry7 */
    598         $carry7 = ($h7 + (1 << 24)) >> 25;
    599         $h8 += $carry7;
    600         $h7 -= $carry7 << 25;
    601 
    602         /** @var int $carry4 */
    603         $carry4 = ($h4 + (1 << 25)) >> 26;
    604         $h5 += $carry4;
    605         $h4 -= $carry4 << 26;
    606         /** @var int $carry8 */
    607         $carry8 = ($h8 + (1 << 25)) >> 26;
    608         $h9 += $carry8;
    609         $h8 -= $carry8 << 26;
    610 
    611         /** @var int $carry9 */
    612         $carry9 = ($h9 + (1 << 24)) >> 25;
    613         $h0 += self::mul($carry9, 19, 5);
    614         $h9 -= $carry9 << 25;
    615 
    616         /** @var int $carry0 */
    617         $carry0 = ($h0 + (1 << 25)) >> 26;
    618         $h1 += $carry0;
    619         $h0 -= $carry0 << 26;
    620 
    621         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
    622             array(
    623                 (int) $h0,
    624                 (int) $h1,
    625                 (int) $h2,
    626                 (int) $h3,
    627                 (int) $h4,
    628                 (int) $h5,
    629                 (int) $h6,
    630                 (int) $h7,
    631                 (int) $h8,
    632                 (int) $h9
    633             )
    634         );
    635     }
    636 
    637     /**
    638      * Get the negative values for each piece of the field element.
    639      *
    640      * h = -f
    641      *
    642      * @internal You should not use this directly from another application
    643      *
    644      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    645      * @return ParagonIE_Sodium_Core_Curve25519_Fe
    646      * @psalm-suppress MixedAssignment
    647      */
    648     public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    649     {
    650         $h = new ParagonIE_Sodium_Core_Curve25519_Fe();
    651         for ($i = 0; $i < 10; ++$i) {
    652             $h[$i] = -$f[$i];
    653         }
    654         return $h;
    655     }
    656 
    657     /**
    658      * Square a field element
    659      *
    660      * h = f * f
    661      *
    662      * @internal You should not use this directly from another application
    663      *
    664      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    665      * @return ParagonIE_Sodium_Core_Curve25519_Fe
    666      */
    667     public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    668     {
    669         $f0 = (int) $f[0];
    670         $f1 = (int) $f[1];
    671         $f2 = (int) $f[2];
    672         $f3 = (int) $f[3];
    673         $f4 = (int) $f[4];
    674         $f5 = (int) $f[5];
    675         $f6 = (int) $f[6];
    676         $f7 = (int) $f[7];
    677         $f8 = (int) $f[8];
    678         $f9 = (int) $f[9];
    679 
    680         /** @var int $f0_2 */
    681         $f0_2 = $f0 << 1;
    682         /** @var int $f1_2 */
    683         $f1_2 = $f1 << 1;
    684         /** @var int $f2_2 */
    685         $f2_2 = $f2 << 1;
    686         /** @var int $f3_2 */
    687         $f3_2 = $f3 << 1;
    688         /** @var int $f4_2 */
    689         $f4_2 = $f4 << 1;
    690         /** @var int $f5_2 */
    691         $f5_2 = $f5 << 1;
    692         /** @var int $f6_2 */
    693         $f6_2 = $f6 << 1;
    694         /** @var int $f7_2 */
    695         $f7_2 = $f7 << 1;
    696         $f5_38 = self::mul($f5, 38, 6);
    697         $f6_19 = self::mul($f6, 19, 5);
    698         $f7_38 = self::mul($f7, 38, 6);
    699         $f8_19 = self::mul($f8, 19, 5);
    700         $f9_38 = self::mul($f9, 38, 6);
    701         $f0f0    = self::mul($f0,    $f0,    25);
    702         $f0f1_2  = self::mul($f0_2,  $f1,    24);
    703         $f0f2_2  = self::mul($f0_2,  $f2,    26);
    704         $f0f3_2  = self::mul($f0_2,  $f3,    24);
    705         $f0f4_2  = self::mul($f0_2,  $f4,    25);
    706         $f0f5_2  = self::mul($f0_2,  $f5,    25);
    707         $f0f6_2  = self::mul($f0_2,  $f6,    25);
    708         $f0f7_2  = self::mul($f0_2,  $f7,    24);
    709         $f0f8_2  = self::mul($f0_2,  $f8,    25);
    710         $f0f9_2  = self::mul($f0_2,  $f9,    25);
    711         $f1f1_2  = self::mul($f1_2,  $f1,    24);
    712         $f1f2_2  = self::mul($f1_2,  $f2,    26);
    713         $f1f3_4  = self::mul($f1_2,  $f3_2,  25);
    714         $f1f4_2  = self::mul($f1_2,  $f4,    25);
    715         $f1f5_4  = self::mul($f1_2,  $f5_2,  26);
    716         $f1f6_2  = self::mul($f1_2,  $f6,    25);
    717         $f1f7_4  = self::mul($f1_2,  $f7_2,  25);
    718         $f1f8_2  = self::mul($f1_2,  $f8,    25);
    719         $f1f9_76 = self::mul($f9_38, $f1_2,  25);
    720         $f2f2    = self::mul($f2,    $f2,    26);
    721         $f2f3_2  = self::mul($f2_2,  $f3,    24);
    722         $f2f4_2  = self::mul($f2_2,  $f4,    25);
    723         $f2f5_2  = self::mul($f2_2,  $f5,    25);
    724         $f2f6_2  = self::mul($f2_2,  $f6,    25);
    725         $f2f7_2  = self::mul($f2_2,  $f7,    25);
    726         $f2f8_38 = self::mul($f8_19, $f2_2,  27);
    727         $f2f9_38 = self::mul($f9_38, $f2,    26);
    728         $f3f3_2  = self::mul($f3_2,  $f3,    25);
    729         $f3f4_2  = self::mul($f3_2,  $f4,    25);
    730         $f3f5_4  = self::mul($f3_2,  $f5_2,  26);
    731         $f3f6_2  = self::mul($f3_2,  $f6,    25);
    732         $f3f7_76 = self::mul($f7_38, $f3_2,  25);
    733         $f3f8_38 = self::mul($f8_19, $f3_2,  25);
    734         $f3f9_76 = self::mul($f9_38, $f3_2,  25);
    735         $f4f4    = self::mul($f4,    $f4,    25);
    736         $f4f5_2  = self::mul($f4_2,  $f5,    25);
    737         $f4f6_38 = self::mul($f6_19, $f4_2,  26);
    738         $f4f7_38 = self::mul($f7_38, $f4,    25);
    739         $f4f8_38 = self::mul($f8_19, $f4_2,  26);
    740         $f4f9_38 = self::mul($f9_38, $f4,    25);
    741         $f5f5_38 = self::mul($f5_38, $f5,    25);
    742         $f5f6_38 = self::mul($f6_19, $f5_2,  26);
    743         $f5f7_76 = self::mul($f7_38, $f5_2,  26);
    744         $f5f8_38 = self::mul($f8_19, $f5_2,  26);
    745         $f5f9_76 = self::mul($f9_38, $f5_2,  26);
    746         $f6f6_19 = self::mul($f6_19, $f6,    25);
    747         $f6f7_38 = self::mul($f7_38, $f6,    25);
    748         $f6f8_38 = self::mul($f8_19, $f6_2,  26);
    749         $f6f9_38 = self::mul($f9_38, $f6,    25);
    750         $f7f7_38 = self::mul($f7_38, $f7,    24);
    751         $f7f8_38 = self::mul($f8_19, $f7_2,  25);
    752         $f7f9_76 = self::mul($f9_38, $f7_2,  25);
    753         $f8f8_19 = self::mul($f8_19, $f8,    25);
    754         $f8f9_38 = self::mul($f9_38, $f8,    25);
    755         $f9f9_38 = self::mul($f9_38, $f9,    25);
    756         $h0 = $f0f0   + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38;
    757         $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
    758         $h2 = $f0f2_2 + $f1f1_2  + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19;
    759         $h3 = $f0f3_2 + $f1f2_2  + $f4f9_38 + $f5f8_38 + $f6f7_38;
    760         $h4 = $f0f4_2 + $f1f3_4  + $f2f2    + $f5f9_76 + $f6f8_38 + $f7f7_38;
    761         $h5 = $f0f5_2 + $f1f4_2  + $f2f3_2  + $f6f9_38 + $f7f8_38;
    762         $h6 = $f0f6_2 + $f1f5_4  + $f2f4_2  + $f3f3_2  + $f7f9_76 + $f8f8_19;
    763         $h7 = $f0f7_2 + $f1f6_2  + $f2f5_2  + $f3f4_2  + $f8f9_38;
    764         $h8 = $f0f8_2 + $f1f7_4  + $f2f6_2  + $f3f5_4  + $f4f4    + $f9f9_38;
    765         $h9 = $f0f9_2 + $f1f8_2  + $f2f7_2  + $f3f6_2  + $f4f5_2;
    766 
    767         /** @var int $carry0 */
    768         $carry0 = ($h0 + (1 << 25)) >> 26;
    769         $h1 += $carry0;
    770         $h0 -= $carry0 << 26;
    771         /** @var int $carry4 */
    772         $carry4 = ($h4 + (1 << 25)) >> 26;
    773         $h5 += $carry4;
    774         $h4 -= $carry4 << 26;
    775 
    776         /** @var int $carry1 */
    777         $carry1 = ($h1 + (1 << 24)) >> 25;
    778         $h2 += $carry1;
    779         $h1 -= $carry1 << 25;
    780         /** @var int $carry5 */
    781         $carry5 = ($h5 + (1 << 24)) >> 25;
    782         $h6 += $carry5;
    783         $h5 -= $carry5 << 25;
    784 
    785         /** @var int $carry2 */
    786         $carry2 = ($h2 + (1 << 25)) >> 26;
    787         $h3 += $carry2;
    788         $h2 -= $carry2 << 26;
    789         /** @var int $carry6 */
    790         $carry6 = ($h6 + (1 << 25)) >> 26;
    791         $h7 += $carry6;
    792         $h6 -= $carry6 << 26;
    793 
    794         /** @var int $carry3 */
    795         $carry3 = ($h3 + (1 << 24)) >> 25;
    796         $h4 += $carry3;
    797         $h3 -= $carry3 << 25;
    798         /** @var int $carry7 */
    799         $carry7 = ($h7 + (1 << 24)) >> 25;
    800         $h8 += $carry7;
    801         $h7 -= $carry7 << 25;
    802 
    803         /** @var int $carry4 */
    804         $carry4 = ($h4 + (1 << 25)) >> 26;
    805         $h5 += $carry4;
    806         $h4 -= $carry4 << 26;
    807         /** @var int $carry8 */
    808         $carry8 = ($h8 + (1 << 25)) >> 26;
    809         $h9 += $carry8;
    810         $h8 -= $carry8 << 26;
    811 
    812         /** @var int $carry9 */
    813         $carry9 = ($h9 + (1 << 24)) >> 25;
    814         $h0 += self::mul($carry9, 19, 5);
    815         $h9 -= $carry9 << 25;
    816 
    817         /** @var int $carry0 */
    818         $carry0 = ($h0 + (1 << 25)) >> 26;
    819         $h1 += $carry0;
    820         $h0 -= $carry0 << 26;
    821 
    822         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
    823             array(
    824                 (int) $h0,
    825                 (int) $h1,
    826                 (int) $h2,
    827                 (int) $h3,
    828                 (int) $h4,
    829                 (int) $h5,
    830                 (int) $h6,
    831                 (int) $h7,
    832                 (int) $h8,
    833                 (int) $h9
    834             )
    835         );
    836     }
    837 
    838 
    839     /**
    840      * Square and double a field element
    841      *
    842      * h = 2 * f * f
    843      *
    844      * @internal You should not use this directly from another application
    845      *
    846      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
    847      * @return ParagonIE_Sodium_Core_Curve25519_Fe
    848      */
    849     public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    850     {
    851         $f0 = (int) $f[0];
    852         $f1 = (int) $f[1];
    853         $f2 = (int) $f[2];
    854         $f3 = (int) $f[3];
    855         $f4 = (int) $f[4];
    856         $f5 = (int) $f[5];
    857         $f6 = (int) $f[6];
    858         $f7 = (int) $f[7];
    859         $f8 = (int) $f[8];
    860         $f9 = (int) $f[9];
    861 
    862         /** @var int $f0_2 */
    863         $f0_2 = $f0 << 1;
    864         /** @var int $f1_2 */
    865         $f1_2 = $f1 << 1;
    866         /** @var int $f2_2 */
    867         $f2_2 = $f2 << 1;
    868         /** @var int $f3_2 */
    869         $f3_2 = $f3 << 1;
    870         /** @var int $f4_2 */
    871         $f4_2 = $f4 << 1;
    872         /** @var int $f5_2 */
    873         $f5_2 = $f5 << 1;
    874         /** @var int $f6_2 */
    875         $f6_2 = $f6 << 1;
    876         /** @var int $f7_2 */
    877         $f7_2 = $f7 << 1;
    878         $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
    879         $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
    880         $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
    881         $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
    882         $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
    883         $f0f0 = self::mul($f0, $f0, 24);
    884         $f0f1_2 = self::mul($f0_2, $f1, 24);
    885         $f0f2_2 = self::mul($f0_2, $f2, 24);
    886         $f0f3_2 = self::mul($f0_2, $f3, 24);
    887         $f0f4_2 = self::mul($f0_2, $f4, 24);
    888         $f0f5_2 = self::mul($f0_2, $f5, 24);
    889         $f0f6_2 = self::mul($f0_2, $f6, 24);
    890         $f0f7_2 = self::mul($f0_2, $f7, 24);
    891         $f0f8_2 = self::mul($f0_2, $f8, 24);
    892         $f0f9_2 = self::mul($f0_2, $f9, 24);
    893         $f1f1_2 = self::mul($f1_2,  $f1, 24);
    894         $f1f2_2 = self::mul($f1_2,  $f2, 24);
    895         $f1f3_4 = self::mul($f1_2,  $f3_2, 24);
    896         $f1f4_2 = self::mul($f1_2,  $f4, 24);
    897         $f1f5_4 = self::mul($f1_2,  $f5_2, 24);
    898         $f1f6_2 = self::mul($f1_2,  $f6, 24);
    899         $f1f7_4 = self::mul($f1_2,  $f7_2, 24);
    900         $f1f8_2 = self::mul($f1_2,  $f8, 24);
    901         $f1f9_76 = self::mul($f9_38, $f1_2, 24);
    902         $f2f2 = self::mul($f2,  $f2, 24);
    903         $f2f3_2 = self::mul($f2_2,  $f3, 24);
    904         $f2f4_2 = self::mul($f2_2,  $f4, 24);
    905         $f2f5_2 = self::mul($f2_2,  $f5, 24);
    906         $f2f6_2 = self::mul($f2_2,  $f6, 24);
    907         $f2f7_2 = self::mul($f2_2,  $f7, 24);
    908         $f2f8_38 = self::mul($f8_19, $f2_2, 25);
    909         $f2f9_38 = self::mul($f9_38, $f2, 24);
    910         $f3f3_2 = self::mul($f3_2,  $f3, 24);
    911         $f3f4_2 = self::mul($f3_2,  $f4, 24);
    912         $f3f5_4 = self::mul($f3_2,  $f5_2, 24);
    913         $f3f6_2 = self::mul($f3_2,  $f6, 24);
    914         $f3f7_76 = self::mul($f7_38, $f3_2, 24);
    915         $f3f8_38 = self::mul($f8_19, $f3_2, 24);
    916         $f3f9_76 = self::mul($f9_38, $f3_2, 24);
    917         $f4f4 = self::mul($f4,  $f4, 24);
    918         $f4f5_2 = self::mul($f4_2,  $f5, 24);
    919         $f4f6_38 = self::mul($f6_19, $f4_2, 25);
    920         $f4f7_38 = self::mul($f7_38, $f4, 24);
    921         $f4f8_38 = self::mul($f8_19, $f4_2, 25);
    922         $f4f9_38 = self::mul($f9_38, $f4, 24);
    923         $f5f5_38 = self::mul($f5_38, $f5, 24);
    924         $f5f6_38 = self::mul($f6_19, $f5_2, 24);
    925         $f5f7_76 = self::mul($f7_38, $f5_2, 24);
    926         $f5f8_38 = self::mul($f8_19, $f5_2, 24);
    927         $f5f9_76 = self::mul($f9_38, $f5_2, 24);
    928         $f6f6_19 = self::mul($f6_19, $f6, 24);
    929         $f6f7_38 = self::mul($f7_38, $f6, 24);
    930         $f6f8_38 = self::mul($f8_19, $f6_2, 25);
    931         $f6f9_38 = self::mul($f9_38, $f6, 24);
    932         $f7f7_38 = self::mul($f7_38, $f7, 24);
    933         $f7f8_38 = self::mul($f8_19, $f7_2, 24);
    934         $f7f9_76 = self::mul($f9_38, $f7_2, 24);
    935         $f8f8_19 = self::mul($f8_19, $f8, 24);
    936         $f8f9_38 = self::mul($f9_38, $f8, 24);
    937         $f9f9_38 = self::mul($f9_38, $f9, 24);
    938 
    939         /** @var int $h0 */
    940         $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1;
    941         /** @var int $h1 */
    942         $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1;
    943         /** @var int $h2 */
    944         $h2 = (int) ($f0f2_2 + $f1f1_2  + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1;
    945         /** @var int $h3 */
    946         $h3 = (int) ($f0f3_2 + $f1f2_2  + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1;
    947         /** @var int $h4 */
    948         $h4 = (int) ($f0f4_2 + $f1f3_4  + $f2f2    + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1;
    949         /** @var int $h5 */
    950         $h5 = (int) ($f0f5_2 + $f1f4_2  + $f2f3_2  + $f6f9_38 + $f7f8_38) << 1;
    951         /** @var int $h6 */
    952         $h6 = (int) ($f0f6_2 + $f1f5_4  + $f2f4_2  + $f3f3_2  + $f7f9_76 + $f8f8_19) << 1;
    953         /** @var int $h7 */
    954         $h7 = (int) ($f0f7_2 + $f1f6_2  + $f2f5_2  + $f3f4_2  + $f8f9_38) << 1;
    955         /** @var int $h8 */
    956         $h8 = (int) ($f0f8_2 + $f1f7_4  + $f2f6_2  + $f3f5_4  + $f4f4    + $f9f9_38) << 1;
    957         /** @var int $h9 */
    958         $h9 = (int) ($f0f9_2 + $f1f8_2  + $f2f7_2  + $f3f6_2  + $f4f5_2) << 1;
    959 
    960         /** @var int $carry0 */
    961         $carry0 = ($h0 + (1 << 25)) >> 26;
    962         $h1 += $carry0;
    963         $h0 -= $carry0 << 26;
    964         /** @var int $carry4 */
    965         $carry4 = ($h4 + (1 << 25)) >> 26;
    966         $h5 += $carry4;
    967         $h4 -= $carry4 << 26;
    968 
    969         /** @var int $carry1 */
    970         $carry1 = ($h1 + (1 << 24)) >> 25;
    971         $h2 += $carry1;
    972         $h1 -= $carry1 << 25;
    973         /** @var int $carry5 */
    974         $carry5 = ($h5 + (1 << 24)) >> 25;
    975         $h6 += $carry5;
    976         $h5 -= $carry5 << 25;
    977 
    978         /** @var int $carry2 */
    979         $carry2 = ($h2 + (1 << 25)) >> 26;
    980         $h3 += $carry2;
    981         $h2 -= $carry2 << 26;
    982         /** @var int $carry6 */
    983         $carry6 = ($h6 + (1 << 25)) >> 26;
    984         $h7 += $carry6;
    985         $h6 -= $carry6 << 26;
    986 
    987         /** @var int $carry3 */
    988         $carry3 = ($h3 + (1 << 24)) >> 25;
    989         $h4 += $carry3;
    990         $h3 -= $carry3 << 25;
    991         /** @var int $carry7 */
    992         $carry7 = ($h7 + (1 << 24)) >> 25;
    993         $h8 += $carry7;
    994         $h7 -= $carry7 << 25;
    995 
    996         /** @var int $carry4 */
    997         $carry4 = ($h4 + (1 << 25)) >> 26;
    998         $h5 += $carry4;
    999         $h4 -= $carry4 << 26;
   1000         /** @var int $carry8 */
   1001         $carry8 = ($h8 + (1 << 25)) >> 26;
   1002         $h9 += $carry8;
   1003         $h8 -= $carry8 << 26;
   1004 
   1005         /** @var int $carry9 */
   1006         $carry9 = ($h9 + (1 << 24)) >> 25;
   1007         $h0 += self::mul($carry9, 19, 5);
   1008         $h9 -= $carry9 << 25;
   1009 
   1010         /** @var int $carry0 */
   1011         $carry0 = ($h0 + (1 << 25)) >> 26;
   1012         $h1 += $carry0;
   1013         $h0 -= $carry0 << 26;
   1014 
   1015         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
   1016             array(
   1017                 (int) $h0,
   1018                 (int) $h1,
   1019                 (int) $h2,
   1020                 (int) $h3,
   1021                 (int) $h4,
   1022                 (int) $h5,
   1023                 (int) $h6,
   1024                 (int) $h7,
   1025                 (int) $h8,
   1026                 (int) $h9
   1027             )
   1028         );
   1029     }
   1030 
   1031     /**
   1032      * @internal You should not use this directly from another application
   1033      *
   1034      * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
   1035      * @return ParagonIE_Sodium_Core_Curve25519_Fe
   1036      */
   1037     public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z)
   1038     {
   1039         $z = clone $Z;
   1040         $t0 = self::fe_sq($z);
   1041         $t1 = self::fe_sq($t0);
   1042         $t1 = self::fe_sq($t1);
   1043         $t1 = self::fe_mul($z, $t1);
   1044         $t0 = self::fe_mul($t0, $t1);
   1045         $t2 = self::fe_sq($t0);
   1046         $t1 = self::fe_mul($t1, $t2);
   1047         $t2 = self::fe_sq($t1);
   1048         for ($i = 1; $i < 5; ++$i) {
   1049             $t2 = self::fe_sq($t2);
   1050         }
   1051         $t1 = self::fe_mul($t2, $t1);
   1052         $t2 = self::fe_sq($t1);
   1053         for ($i = 1; $i < 10; ++$i) {
   1054             $t2 = self::fe_sq($t2);
   1055         }
   1056         $t2 = self::fe_mul($t2, $t1);
   1057         $t3 = self::fe_sq($t2);
   1058         for ($i = 1; $i < 20; ++$i) {
   1059             $t3 = self::fe_sq($t3);
   1060         }
   1061         $t2 = self::fe_mul($t3, $t2);
   1062         $t2 = self::fe_sq($t2);
   1063         for ($i = 1; $i < 10; ++$i) {
   1064             $t2 = self::fe_sq($t2);
   1065         }
   1066         $t1 = self::fe_mul($t2, $t1);
   1067         $t2 = self::fe_sq($t1);
   1068         for ($i = 1; $i < 50; ++$i) {
   1069             $t2 = self::fe_sq($t2);
   1070         }
   1071         $t2 = self::fe_mul($t2, $t1);
   1072         $t3 = self::fe_sq($t2);
   1073         for ($i = 1; $i < 100; ++$i) {
   1074             $t3 = self::fe_sq($t3);
   1075         }
   1076         $t2 = self::fe_mul($t3, $t2);
   1077         $t2 = self::fe_sq($t2);
   1078         for ($i = 1; $i < 50; ++$i) {
   1079             $t2 = self::fe_sq($t2);
   1080         }
   1081         $t1 = self::fe_mul($t2, $t1);
   1082         $t1 = self::fe_sq($t1);
   1083         for ($i = 1; $i < 5; ++$i) {
   1084             $t1 = self::fe_sq($t1);
   1085         }
   1086         return self::fe_mul($t1, $t0);
   1087     }
   1088 
   1089     /**
   1090      * @internal You should not use this directly from another application
   1091      *
   1092      * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
   1093      *
   1094      * @param ParagonIE_Sodium_Core_Curve25519_Fe $z
   1095      * @return ParagonIE_Sodium_Core_Curve25519_Fe
   1096      */
   1097     public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z)
   1098     {
   1099         # fe_sq(t0, z);
   1100         # fe_sq(t1, t0);
   1101         # fe_sq(t1, t1);
   1102         # fe_mul(t1, z, t1);
   1103         # fe_mul(t0, t0, t1);
   1104         # fe_sq(t0, t0);
   1105         # fe_mul(t0, t1, t0);
   1106         # fe_sq(t1, t0);
   1107         $t0 = self::fe_sq($z);
   1108         $t1 = self::fe_sq($t0);
   1109         $t1 = self::fe_sq($t1);
   1110         $t1 = self::fe_mul($z, $t1);
   1111         $t0 = self::fe_mul($t0, $t1);
   1112         $t0 = self::fe_sq($t0);
   1113         $t0 = self::fe_mul($t1, $t0);
   1114         $t1 = self::fe_sq($t0);
   1115 
   1116         # for (i = 1; i < 5; ++i) {
   1117         #     fe_sq(t1, t1);
   1118         # }
   1119         for ($i = 1; $i < 5; ++$i) {
   1120             $t1 = self::fe_sq($t1);
   1121         }
   1122 
   1123         # fe_mul(t0, t1, t0);
   1124         # fe_sq(t1, t0);
   1125         $t0 = self::fe_mul($t1, $t0);
   1126         $t1 = self::fe_sq($t0);
   1127 
   1128         # for (i = 1; i < 10; ++i) {
   1129         #     fe_sq(t1, t1);
   1130         # }
   1131         for ($i = 1; $i < 10; ++$i) {
   1132             $t1 = self::fe_sq($t1);
   1133         }
   1134 
   1135         # fe_mul(t1, t1, t0);
   1136         # fe_sq(t2, t1);
   1137         $t1 = self::fe_mul($t1, $t0);
   1138         $t2 = self::fe_sq($t1);
   1139 
   1140         # for (i = 1; i < 20; ++i) {
   1141         #     fe_sq(t2, t2);
   1142         # }
   1143         for ($i = 1; $i < 20; ++$i) {
   1144             $t2 = self::fe_sq($t2);
   1145         }
   1146 
   1147         # fe_mul(t1, t2, t1);
   1148         # fe_sq(t1, t1);
   1149         $t1 = self::fe_mul($t2, $t1);
   1150         $t1 = self::fe_sq($t1);
   1151 
   1152         # for (i = 1; i < 10; ++i) {
   1153         #     fe_sq(t1, t1);
   1154         # }
   1155         for ($i = 1; $i < 10; ++$i) {
   1156             $t1 = self::fe_sq($t1);
   1157         }
   1158 
   1159         # fe_mul(t0, t1, t0);
   1160         # fe_sq(t1, t0);
   1161         $t0 = self::fe_mul($t1, $t0);
   1162         $t1 = self::fe_sq($t0);
   1163 
   1164         # for (i = 1; i < 50; ++i) {
   1165         #     fe_sq(t1, t1);
   1166         # }
   1167         for ($i = 1; $i < 50; ++$i) {
   1168             $t1 = self::fe_sq($t1);
   1169         }
   1170 
   1171         # fe_mul(t1, t1, t0);
   1172         # fe_sq(t2, t1);
   1173         $t1 = self::fe_mul($t1, $t0);
   1174         $t2 = self::fe_sq($t1);
   1175 
   1176         # for (i = 1; i < 100; ++i) {
   1177         #     fe_sq(t2, t2);
   1178         # }
   1179         for ($i = 1; $i < 100; ++$i) {
   1180             $t2 = self::fe_sq($t2);
   1181         }
   1182 
   1183         # fe_mul(t1, t2, t1);
   1184         # fe_sq(t1, t1);
   1185         $t1 = self::fe_mul($t2, $t1);
   1186         $t1 = self::fe_sq($t1);
   1187 
   1188         # for (i = 1; i < 50; ++i) {
   1189         #     fe_sq(t1, t1);
   1190         # }
   1191         for ($i = 1; $i < 50; ++$i) {
   1192             $t1 = self::fe_sq($t1);
   1193         }
   1194 
   1195         # fe_mul(t0, t1, t0);
   1196         # fe_sq(t0, t0);
   1197         # fe_sq(t0, t0);
   1198         # fe_mul(out, t0, z);
   1199         $t0 = self::fe_mul($t1, $t0);
   1200         $t0 = self::fe_sq($t0);
   1201         $t0 = self::fe_sq($t0);
   1202         return self::fe_mul($t0, $z);
   1203     }
   1204 
   1205     /**
   1206      * Subtract two field elements.
   1207      *
   1208      * h = f - g
   1209      *
   1210      * Preconditions:
   1211      * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
   1212      * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
   1213      *
   1214      * Postconditions:
   1215      * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
   1216      *
   1217      * @internal You should not use this directly from another application
   1218      *
   1219      * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
   1220      * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
   1221      * @return ParagonIE_Sodium_Core_Curve25519_Fe
   1222      * @psalm-suppress MixedOperand
   1223      */
   1224     public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g)
   1225     {
   1226         return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
   1227             array(
   1228                 (int) ($f[0] - $g[0]),
   1229                 (int) ($f[1] - $g[1]),
   1230                 (int) ($f[2] - $g[2]),
   1231                 (int) ($f[3] - $g[3]),
   1232                 (int) ($f[4] - $g[4]),
   1233                 (int) ($f[5] - $g[5]),
   1234                 (int) ($f[6] - $g[6]),
   1235                 (int) ($f[7] - $g[7]),
   1236                 (int) ($f[8] - $g[8]),
   1237                 (int) ($f[9] - $g[9])
   1238             )
   1239         );
   1240     }
   1241 
   1242     /**
   1243      * Add two group elements.
   1244      *
   1245      * r = p + q
   1246      *
   1247      * @internal You should not use this directly from another application
   1248      *
   1249      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1250      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
   1251      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
   1252      */
   1253     public static function ge_add(
   1254         ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
   1255         ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
   1256     ) {
   1257         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
   1258         $r->X = self::fe_add($p->Y, $p->X);
   1259         $r->Y = self::fe_sub($p->Y, $p->X);
   1260         $r->Z = self::fe_mul($r->X, $q->YplusX);
   1261         $r->Y = self::fe_mul($r->Y, $q->YminusX);
   1262         $r->T = self::fe_mul($q->T2d, $p->T);
   1263         $r->X = self::fe_mul($p->Z, $q->Z);
   1264         $t0   = self::fe_add($r->X, $r->X);
   1265         $r->X = self::fe_sub($r->Z, $r->Y);
   1266         $r->Y = self::fe_add($r->Z, $r->Y);
   1267         $r->Z = self::fe_add($t0, $r->T);
   1268         $r->T = self::fe_sub($t0, $r->T);
   1269         return $r;
   1270     }
   1271 
   1272     /**
   1273      * @internal You should not use this directly from another application
   1274      *
   1275      * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
   1276      * @param string $a
   1277      * @return array<int, mixed>
   1278      * @throws SodiumException
   1279      * @throws TypeError
   1280      */
   1281     public static function slide($a)
   1282     {
   1283         if (self::strlen($a) < 256) {
   1284             if (self::strlen($a) < 16) {
   1285                 $a = str_pad($a, 256, '0', STR_PAD_RIGHT);
   1286             }
   1287         }
   1288         /** @var array<int, int> $r */
   1289         $r = array();
   1290 
   1291         /** @var int $i */
   1292         for ($i = 0; $i < 256; ++$i) {
   1293             $r[$i] = (int) (
   1294                 1 & (
   1295                     self::chrToInt($a[(int) ($i >> 3)])
   1296                         >>
   1297                     ($i & 7)
   1298                 )
   1299             );
   1300         }
   1301 
   1302         for ($i = 0;$i < 256;++$i) {
   1303             if ($r[$i]) {
   1304                 for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
   1305                     if ($r[$i + $b]) {
   1306                         if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
   1307                             $r[$i] += $r[$i + $b] << $b;
   1308                             $r[$i + $b] = 0;
   1309                         } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
   1310                             $r[$i] -= $r[$i + $b] << $b;
   1311                             for ($k = $i + $b; $k < 256; ++$k) {
   1312                                 if (!$r[$k]) {
   1313                                     $r[$k] = 1;
   1314                                     break;
   1315                                 }
   1316                                 $r[$k] = 0;
   1317                             }
   1318                         } else {
   1319                             break;
   1320                         }
   1321                     }
   1322                 }
   1323             }
   1324         }
   1325         return $r;
   1326     }
   1327 
   1328     /**
   1329      * @internal You should not use this directly from another application
   1330      *
   1331      * @param string $s
   1332      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
   1333      * @throws SodiumException
   1334      * @throws TypeError
   1335      */
   1336     public static function ge_frombytes_negate_vartime($s)
   1337     {
   1338         static $d = null;
   1339         if (!$d) {
   1340             $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
   1341         }
   1342 
   1343         # fe_frombytes(h->Y,s);
   1344         # fe_1(h->Z);
   1345         $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
   1346             self::fe_0(),
   1347             self::fe_frombytes($s),
   1348             self::fe_1()
   1349         );
   1350 
   1351         # fe_sq(u,h->Y);
   1352         # fe_mul(v,u,d);
   1353         # fe_sub(u,u,h->Z);       /* u = y^2-1 */
   1354         # fe_add(v,v,h->Z);       /* v = dy^2+1 */
   1355         $u = self::fe_sq($h->Y);
   1356         /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
   1357         $v = self::fe_mul($u, $d);
   1358         $u = self::fe_sub($u, $h->Z); /* u =  y^2 - 1 */
   1359         $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
   1360 
   1361         # fe_sq(v3,v);
   1362         # fe_mul(v3,v3,v);        /* v3 = v^3 */
   1363         # fe_sq(h->X,v3);
   1364         # fe_mul(h->X,h->X,v);
   1365         # fe_mul(h->X,h->X,u);    /* x = uv^7 */
   1366         $v3 = self::fe_sq($v);
   1367         $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
   1368         $h->X = self::fe_sq($v3);
   1369         $h->X = self::fe_mul($h->X, $v);
   1370         $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
   1371 
   1372         # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
   1373         # fe_mul(h->X,h->X,v3);
   1374         # fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
   1375         $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
   1376         $h->X = self::fe_mul($h->X, $v3);
   1377         $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
   1378 
   1379         # fe_sq(vxx,h->X);
   1380         # fe_mul(vxx,vxx,v);
   1381         # fe_sub(check,vxx,u);    /* vx^2-u */
   1382         $vxx = self::fe_sq($h->X);
   1383         $vxx = self::fe_mul($vxx, $v);
   1384         $check = self::fe_sub($vxx, $u); /* vx^2 - u */
   1385 
   1386         # if (fe_isnonzero(check)) {
   1387         #     fe_add(check,vxx,u);  /* vx^2+u */
   1388         #     if (fe_isnonzero(check)) {
   1389         #         return -1;
   1390         #     }
   1391         #     fe_mul(h->X,h->X,sqrtm1);
   1392         # }
   1393         if (self::fe_isnonzero($check)) {
   1394             $check = self::fe_add($vxx, $u); /* vx^2 + u */
   1395             if (self::fe_isnonzero($check)) {
   1396                 throw new RangeException('Internal check failed.');
   1397             }
   1398             $h->X = self::fe_mul(
   1399                 $h->X,
   1400                 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
   1401             );
   1402         }
   1403 
   1404         # if (fe_isnegative(h->X) == (s[31] >> 7)) {
   1405         #     fe_neg(h->X,h->X);
   1406         # }
   1407         $i = self::chrToInt($s[31]);
   1408         if (self::fe_isnegative($h->X) === ($i >> 7)) {
   1409             $h->X = self::fe_neg($h->X);
   1410         }
   1411 
   1412         # fe_mul(h->T,h->X,h->Y);
   1413         $h->T = self::fe_mul($h->X, $h->Y);
   1414         return $h;
   1415     }
   1416 
   1417     /**
   1418      * @internal You should not use this directly from another application
   1419      *
   1420      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
   1421      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1422      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
   1423      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
   1424      */
   1425     public static function ge_madd(
   1426         ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
   1427         ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
   1428         ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
   1429     ) {
   1430         $r = clone $R;
   1431         $r->X = self::fe_add($p->Y, $p->X);
   1432         $r->Y = self::fe_sub($p->Y, $p->X);
   1433         $r->Z = self::fe_mul($r->X, $q->yplusx);
   1434         $r->Y = self::fe_mul($r->Y, $q->yminusx);
   1435         $r->T = self::fe_mul($q->xy2d, $p->T);
   1436         $t0 = self::fe_add(clone $p->Z, clone $p->Z);
   1437         $r->X = self::fe_sub($r->Z, $r->Y);
   1438         $r->Y = self::fe_add($r->Z, $r->Y);
   1439         $r->Z = self::fe_add($t0, $r->T);
   1440         $r->T = self::fe_sub($t0, $r->T);
   1441 
   1442         return $r;
   1443     }
   1444 
   1445     /**
   1446      * @internal You should not use this directly from another application
   1447      *
   1448      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
   1449      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1450      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
   1451      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
   1452      */
   1453     public static function ge_msub(
   1454         ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
   1455         ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
   1456         ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
   1457     ) {
   1458         $r = clone $R;
   1459 
   1460         $r->X = self::fe_add($p->Y, $p->X);
   1461         $r->Y = self::fe_sub($p->Y, $p->X);
   1462         $r->Z = self::fe_mul($r->X, $q->yminusx);
   1463         $r->Y = self::fe_mul($r->Y, $q->yplusx);
   1464         $r->T = self::fe_mul($q->xy2d, $p->T);
   1465         $t0 = self::fe_add($p->Z, $p->Z);
   1466         $r->X = self::fe_sub($r->Z, $r->Y);
   1467         $r->Y = self::fe_add($r->Z, $r->Y);
   1468         $r->Z = self::fe_sub($t0, $r->T);
   1469         $r->T = self::fe_add($t0, $r->T);
   1470 
   1471         return $r;
   1472     }
   1473 
   1474     /**
   1475      * @internal You should not use this directly from another application
   1476      *
   1477      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
   1478      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
   1479      */
   1480     public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
   1481     {
   1482         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
   1483         $r->X = self::fe_mul($p->X, $p->T);
   1484         $r->Y = self::fe_mul($p->Y, $p->Z);
   1485         $r->Z = self::fe_mul($p->Z, $p->T);
   1486         return $r;
   1487     }
   1488 
   1489     /**
   1490      * @internal You should not use this directly from another application
   1491      *
   1492      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
   1493      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
   1494      */
   1495     public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
   1496     {
   1497         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
   1498         $r->X = self::fe_mul($p->X, $p->T);
   1499         $r->Y = self::fe_mul($p->Y, $p->Z);
   1500         $r->Z = self::fe_mul($p->Z, $p->T);
   1501         $r->T = self::fe_mul($p->X, $p->Y);
   1502         return $r;
   1503     }
   1504 
   1505     /**
   1506      * @internal You should not use this directly from another application
   1507      *
   1508      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
   1509      */
   1510     public static function ge_p2_0()
   1511     {
   1512         return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
   1513             self::fe_0(),
   1514             self::fe_1(),
   1515             self::fe_1()
   1516         );
   1517     }
   1518 
   1519     /**
   1520      * @internal You should not use this directly from another application
   1521      *
   1522      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
   1523      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
   1524      */
   1525     public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p)
   1526     {
   1527         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
   1528 
   1529         $r->X = self::fe_sq($p->X);
   1530         $r->Z = self::fe_sq($p->Y);
   1531         $r->T = self::fe_sq2($p->Z);
   1532         $r->Y = self::fe_add($p->X, $p->Y);
   1533         $t0   = self::fe_sq($r->Y);
   1534         $r->Y = self::fe_add($r->Z, $r->X);
   1535         $r->Z = self::fe_sub($r->Z, $r->X);
   1536         $r->X = self::fe_sub($t0, $r->Y);
   1537         $r->T = self::fe_sub($r->T, $r->Z);
   1538 
   1539         return $r;
   1540     }
   1541 
   1542     /**
   1543      * @internal You should not use this directly from another application
   1544      *
   1545      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
   1546      */
   1547     public static function ge_p3_0()
   1548     {
   1549         return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
   1550             self::fe_0(),
   1551             self::fe_1(),
   1552             self::fe_1(),
   1553             self::fe_0()
   1554         );
   1555     }
   1556 
   1557     /**
   1558      * @internal You should not use this directly from another application
   1559      *
   1560      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1561      * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
   1562      */
   1563     public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
   1564     {
   1565         static $d2 = null;
   1566         if ($d2 === null) {
   1567             $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
   1568         }
   1569         /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
   1570         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
   1571         $r->YplusX = self::fe_add($p->Y, $p->X);
   1572         $r->YminusX = self::fe_sub($p->Y, $p->X);
   1573         $r->Z = self::fe_copy($p->Z);
   1574         $r->T2d = self::fe_mul($p->T, $d2);
   1575         return $r;
   1576     }
   1577 
   1578     /**
   1579      * @internal You should not use this directly from another application
   1580      *
   1581      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1582      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
   1583      */
   1584     public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
   1585     {
   1586         return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
   1587             self::fe_copy($p->X),
   1588             self::fe_copy($p->Y),
   1589             self::fe_copy($p->Z)
   1590         );
   1591     }
   1592 
   1593     /**
   1594      * @internal You should not use this directly from another application
   1595      *
   1596      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
   1597      * @return string
   1598      * @throws SodiumException
   1599      * @throws TypeError
   1600      */
   1601     public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
   1602     {
   1603         $recip = self::fe_invert($h->Z);
   1604         $x = self::fe_mul($h->X, $recip);
   1605         $y = self::fe_mul($h->Y, $recip);
   1606         $s = self::fe_tobytes($y);
   1607         $s[31] = self::intToChr(
   1608             self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
   1609         );
   1610         return $s;
   1611     }
   1612 
   1613     /**
   1614      * @internal You should not use this directly from another application
   1615      *
   1616      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1617      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
   1618      */
   1619     public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
   1620     {
   1621         $q = self::ge_p3_to_p2($p);
   1622         return self::ge_p2_dbl($q);
   1623     }
   1624 
   1625     /**
   1626      * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
   1627      */
   1628     public static function ge_precomp_0()
   1629     {
   1630         return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
   1631             self::fe_1(),
   1632             self::fe_1(),
   1633             self::fe_0()
   1634         );
   1635     }
   1636 
   1637     /**
   1638      * @internal You should not use this directly from another application
   1639      *
   1640      * @param int $b
   1641      * @param int $c
   1642      * @return int
   1643      */
   1644     public static function equal($b, $c)
   1645     {
   1646         return (int) ((($b ^ $c) - 1) >> 31) & 1;
   1647     }
   1648 
   1649     /**
   1650      * @internal You should not use this directly from another application
   1651      *
   1652      * @param int|string $char
   1653      * @return int (1 = yes, 0 = no)
   1654      * @throws SodiumException
   1655      * @throws TypeError
   1656      */
   1657     public static function negative($char)
   1658     {
   1659         if (is_int($char)) {
   1660             return ($char >> 63) & 1;
   1661         }
   1662         $x = self::chrToInt(self::substr($char, 0, 1));
   1663         return (int) ($x >> 63);
   1664     }
   1665 
   1666     /**
   1667      * Conditional move
   1668      *
   1669      * @internal You should not use this directly from another application
   1670      *
   1671      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
   1672      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
   1673      * @param int $b
   1674      * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
   1675      */
   1676     public static function cmov(
   1677         ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
   1678         ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
   1679         $b
   1680     ) {
   1681         if (!is_int($b)) {
   1682             throw new InvalidArgumentException('Expected an integer.');
   1683         }
   1684         return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
   1685             self::fe_cmov($t->yplusx,  $u->yplusx,  $b),
   1686             self::fe_cmov($t->yminusx, $u->yminusx, $b),
   1687             self::fe_cmov($t->xy2d,    $u->xy2d,    $b)
   1688         );
   1689     }
   1690 
   1691     /**
   1692      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t
   1693      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u
   1694      * @param int $b
   1695      * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
   1696      */
   1697     public static function ge_cmov_cached(
   1698         ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t,
   1699         ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u,
   1700         $b
   1701     ) {
   1702         $b &= 1;
   1703         $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
   1704         $ret->YplusX  = self::fe_cmov($t->YplusX,  $u->YplusX,  $b);
   1705         $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b);
   1706         $ret->Z       = self::fe_cmov($t->Z,       $u->Z,       $b);
   1707         $ret->T2d     = self::fe_cmov($t->T2d,     $u->T2d,     $b);
   1708         return $ret;
   1709     }
   1710 
   1711     /**
   1712      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached
   1713      * @param int $b
   1714      * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
   1715      * @throws SodiumException
   1716      */
   1717     public static function ge_cmov8_cached(array $cached, $b)
   1718     {
   1719         // const unsigned char bnegative = negative(b);
   1720         // const unsigned char babs      = b - (((-bnegative) & b) * ((signed char) 1 << 1));
   1721         $bnegative = self::negative($b);
   1722         $babs = $b - (((-$bnegative) & $b) << 1);
   1723 
   1724         // ge25519_cached_0(t);
   1725         $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
   1726             self::fe_1(),
   1727             self::fe_1(),
   1728             self::fe_1(),
   1729             self::fe_0()
   1730         );
   1731 
   1732         // ge25519_cmov_cached(t, &cached[0], equal(babs, 1));
   1733         // ge25519_cmov_cached(t, &cached[1], equal(babs, 2));
   1734         // ge25519_cmov_cached(t, &cached[2], equal(babs, 3));
   1735         // ge25519_cmov_cached(t, &cached[3], equal(babs, 4));
   1736         // ge25519_cmov_cached(t, &cached[4], equal(babs, 5));
   1737         // ge25519_cmov_cached(t, &cached[5], equal(babs, 6));
   1738         // ge25519_cmov_cached(t, &cached[6], equal(babs, 7));
   1739         // ge25519_cmov_cached(t, &cached[7], equal(babs, 8));
   1740         for ($x = 0; $x < 8; ++$x) {
   1741             $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1));
   1742         }
   1743 
   1744         // fe25519_copy(minust.YplusX, t->YminusX);
   1745         // fe25519_copy(minust.YminusX, t->YplusX);
   1746         // fe25519_copy(minust.Z, t->Z);
   1747         // fe25519_neg(minust.T2d, t->T2d);
   1748         $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
   1749             self::fe_copy($t->YminusX),
   1750             self::fe_copy($t->YplusX),
   1751             self::fe_copy($t->Z),
   1752             self::fe_neg($t->T2d)
   1753         );
   1754         return self::ge_cmov_cached($t, $minust, $bnegative);
   1755     }
   1756 
   1757     /**
   1758      * @internal You should not use this directly from another application
   1759      *
   1760      * @param int $pos
   1761      * @param int $b
   1762      * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
   1763      * @throws SodiumException
   1764      * @throws TypeError
   1765      * @psalm-suppress MixedArgument
   1766      * @psalm-suppress MixedArrayAccess
   1767      * @psalm-suppress MixedArrayOffset
   1768      */
   1769     public static function ge_select($pos = 0, $b = 0)
   1770     {
   1771         static $base = null;
   1772         if ($base === null) {
   1773             $base = array();
   1774             /** @var int $i */
   1775             foreach (self::$base as $i => $bas) {
   1776                 for ($j = 0; $j < 8; ++$j) {
   1777                     $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
   1778                         ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
   1779                         ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
   1780                         ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
   1781                     );
   1782                 }
   1783             }
   1784         }
   1785         /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
   1786         if (!is_int($pos)) {
   1787             throw new InvalidArgumentException('Position must be an integer');
   1788         }
   1789         if ($pos < 0 || $pos > 31) {
   1790             throw new RangeException('Position is out of range [0, 31]');
   1791         }
   1792 
   1793         /** @var int $bnegative */
   1794         $bnegative = self::negative($b);
   1795         /** @var int $babs */
   1796         $babs = $b - (((-$bnegative) & $b) << 1);
   1797 
   1798         $t = self::ge_precomp_0();
   1799         for ($i = 0; $i < 8; ++$i) {
   1800             $t = self::cmov(
   1801                 $t,
   1802                 $base[$pos][$i],
   1803                 self::equal($babs, $i + 1)
   1804             );
   1805         }
   1806         $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
   1807             self::fe_copy($t->yminusx),
   1808             self::fe_copy($t->yplusx),
   1809             self::fe_neg($t->xy2d)
   1810         );
   1811         return self::cmov($t, $minusT, $bnegative);
   1812     }
   1813 
   1814     /**
   1815      * Subtract two group elements.
   1816      *
   1817      * r = p - q
   1818      *
   1819      * @internal You should not use this directly from another application
   1820      *
   1821      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1822      * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
   1823      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
   1824      */
   1825     public static function ge_sub(
   1826         ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
   1827         ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
   1828     ) {
   1829         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
   1830 
   1831         $r->X = self::fe_add($p->Y, $p->X);
   1832         $r->Y = self::fe_sub($p->Y, $p->X);
   1833         $r->Z = self::fe_mul($r->X, $q->YminusX);
   1834         $r->Y = self::fe_mul($r->Y, $q->YplusX);
   1835         $r->T = self::fe_mul($q->T2d, $p->T);
   1836         $r->X = self::fe_mul($p->Z, $q->Z);
   1837         $t0 = self::fe_add($r->X, $r->X);
   1838         $r->X = self::fe_sub($r->Z, $r->Y);
   1839         $r->Y = self::fe_add($r->Z, $r->Y);
   1840         $r->Z = self::fe_sub($t0, $r->T);
   1841         $r->T = self::fe_add($t0, $r->T);
   1842 
   1843         return $r;
   1844     }
   1845 
   1846     /**
   1847      * Convert a group element to a byte string.
   1848      *
   1849      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
   1850      * @return string
   1851      * @throws SodiumException
   1852      * @throws TypeError
   1853      */
   1854     public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
   1855     {
   1856         $recip = self::fe_invert($h->Z);
   1857         $x = self::fe_mul($h->X, $recip);
   1858         $y = self::fe_mul($h->Y, $recip);
   1859         $s = self::fe_tobytes($y);
   1860         $s[31] = self::intToChr(
   1861             self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
   1862         );
   1863         return $s;
   1864     }
   1865 
   1866     /**
   1867      * @internal You should not use this directly from another application
   1868      *
   1869      * @param string $a
   1870      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
   1871      * @param string $b
   1872      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
   1873      * @throws SodiumException
   1874      * @throws TypeError
   1875      * @psalm-suppress MixedArgument
   1876      * @psalm-suppress MixedArrayAccess
   1877      */
   1878     public static function ge_double_scalarmult_vartime(
   1879         $a,
   1880         ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
   1881         $b
   1882     ) {
   1883         /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
   1884         $Ai = array();
   1885 
   1886         /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
   1887         static $Bi = array();
   1888         if (!$Bi) {
   1889             for ($i = 0; $i < 8; ++$i) {
   1890                 $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
   1891                     ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
   1892                     ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
   1893                     ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
   1894                 );
   1895             }
   1896         }
   1897         for ($i = 0; $i < 8; ++$i) {
   1898             $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
   1899                 self::fe_0(),
   1900                 self::fe_0(),
   1901                 self::fe_0(),
   1902                 self::fe_0()
   1903             );
   1904         }
   1905 
   1906         # slide(aslide,a);
   1907         # slide(bslide,b);
   1908         /** @var array<int, int> $aslide */
   1909         $aslide = self::slide($a);
   1910         /** @var array<int, int> $bslide */
   1911         $bslide = self::slide($b);
   1912 
   1913         # ge_p3_to_cached(&Ai[0],A);
   1914         # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
   1915         $Ai[0] = self::ge_p3_to_cached($A);
   1916         $t = self::ge_p3_dbl($A);
   1917         $A2 = self::ge_p1p1_to_p3($t);
   1918 
   1919         # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
   1920         # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
   1921         # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
   1922         # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
   1923         # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
   1924         # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
   1925         # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
   1926         for ($i = 0; $i < 7; ++$i) {
   1927             $t = self::ge_add($A2, $Ai[$i]);
   1928             $u = self::ge_p1p1_to_p3($t);
   1929             $Ai[$i + 1] = self::ge_p3_to_cached($u);
   1930         }
   1931 
   1932         # ge_p2_0(r);
   1933         $r = self::ge_p2_0();
   1934 
   1935         # for (i = 255;i >= 0;--i) {
   1936         #     if (aslide[i] || bslide[i]) break;
   1937         # }
   1938         $i = 255;
   1939         for (; $i >= 0; --$i) {
   1940             if ($aslide[$i] || $bslide[$i]) {
   1941                 break;
   1942             }
   1943         }
   1944 
   1945         # for (;i >= 0;--i) {
   1946         for (; $i >= 0; --$i) {
   1947             # ge_p2_dbl(&t,r);
   1948             $t = self::ge_p2_dbl($r);
   1949 
   1950             # if (aslide[i] > 0) {
   1951             if ($aslide[$i] > 0) {
   1952                 # ge_p1p1_to_p3(&u,&t);
   1953                 # ge_add(&t,&u,&Ai[aslide[i]/2]);
   1954                 $u = self::ge_p1p1_to_p3($t);
   1955                 $t = self::ge_add(
   1956                     $u,
   1957                     $Ai[(int) floor($aslide[$i] / 2)]
   1958                 );
   1959             # } else if (aslide[i] < 0) {
   1960             } elseif ($aslide[$i] < 0) {
   1961                 # ge_p1p1_to_p3(&u,&t);
   1962                 # ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
   1963                 $u = self::ge_p1p1_to_p3($t);
   1964                 $t = self::ge_sub(
   1965                     $u,
   1966                     $Ai[(int) floor(-$aslide[$i] / 2)]
   1967                 );
   1968             }
   1969 
   1970             # if (bslide[i] > 0) {
   1971             if ($bslide[$i] > 0) {
   1972                 /** @var int $index */
   1973                 $index = (int) floor($bslide[$i] / 2);
   1974                 # ge_p1p1_to_p3(&u,&t);
   1975                 # ge_madd(&t,&u,&Bi[bslide[i]/2]);
   1976                 $u = self::ge_p1p1_to_p3($t);
   1977                 $t = self::ge_madd($t, $u, $Bi[$index]);
   1978             # } else if (bslide[i] < 0) {
   1979             } elseif ($bslide[$i] < 0) {
   1980                 /** @var int $index */
   1981                 $index = (int) floor(-$bslide[$i] / 2);
   1982                 # ge_p1p1_to_p3(&u,&t);
   1983                 # ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
   1984                 $u = self::ge_p1p1_to_p3($t);
   1985                 $t = self::ge_msub($t, $u, $Bi[$index]);
   1986             }
   1987             # ge_p1p1_to_p2(r,&t);
   1988             $r = self::ge_p1p1_to_p2($t);
   1989         }
   1990         return $r;
   1991     }
   1992 
   1993     /**
   1994      * @internal You should not use this directly from another application
   1995      *
   1996      * @param string $a
   1997      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
   1998      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
   1999      * @throws SodiumException
   2000      * @throws TypeError
   2001      * @psalm-suppress MixedAssignment
   2002      * @psalm-suppress MixedOperand
   2003      */
   2004     public static function ge_scalarmult($a, $p)
   2005     {
   2006         $e = array_fill(0, 64, 0);
   2007 
   2008         /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */
   2009         $pi = array();
   2010 
   2011         //        ge25519_p3_to_cached(&pi[1 - 1], p);   /* p */
   2012         $pi[0] = self::ge_p3_to_cached($p);
   2013 
   2014         //        ge25519_p3_dbl(&t2, p);
   2015         //        ge25519_p1p1_to_p3(&p2, &t2);
   2016         //        ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */
   2017         $t2 = self::ge_p3_dbl($p);
   2018         $p2 = self::ge_p1p1_to_p3($t2);
   2019         $pi[1] = self::ge_p3_to_cached($p2);
   2020 
   2021         //        ge25519_add_cached(&t3, p, &pi[2 - 1]);
   2022         //        ge25519_p1p1_to_p3(&p3, &t3);
   2023         //        ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */
   2024         $t3 = self::ge_add($p, $pi[1]);
   2025         $p3 = self::ge_p1p1_to_p3($t3);
   2026         $pi[2] = self::ge_p3_to_cached($p3);
   2027 
   2028         //        ge25519_p3_dbl(&t4, &p2);
   2029         //        ge25519_p1p1_to_p3(&p4, &t4);
   2030         //        ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */
   2031         $t4 = self::ge_p3_dbl($p2);
   2032         $p4 = self::ge_p1p1_to_p3($t4);
   2033         $pi[3] = self::ge_p3_to_cached($p4);
   2034 
   2035         //        ge25519_add_cached(&t5, p, &pi[4 - 1]);
   2036         //        ge25519_p1p1_to_p3(&p5, &t5);
   2037         //        ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */
   2038         $t5 = self::ge_add($p, $pi[3]);
   2039         $p5 = self::ge_p1p1_to_p3($t5);
   2040         $pi[4] = self::ge_p3_to_cached($p5);
   2041 
   2042         //        ge25519_p3_dbl(&t6, &p3);
   2043         //        ge25519_p1p1_to_p3(&p6, &t6);
   2044         //        ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */
   2045         $t6 = self::ge_p3_dbl($p3);
   2046         $p6 = self::ge_p1p1_to_p3($t6);
   2047         $pi[5] = self::ge_p3_to_cached($p6);
   2048 
   2049         //        ge25519_add_cached(&t7, p, &pi[6 - 1]);
   2050         //        ge25519_p1p1_to_p3(&p7, &t7);
   2051         //        ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */
   2052         $t7 = self::ge_add($p, $pi[5]);
   2053         $p7 = self::ge_p1p1_to_p3($t7);
   2054         $pi[6] = self::ge_p3_to_cached($p7);
   2055 
   2056         //        ge25519_p3_dbl(&t8, &p4);
   2057         //        ge25519_p1p1_to_p3(&p8, &t8);
   2058         //        ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */
   2059         $t8 = self::ge_p3_dbl($p4);
   2060         $p8 = self::ge_p1p1_to_p3($t8);
   2061         $pi[7] = self::ge_p3_to_cached($p8);
   2062 
   2063 
   2064         //        for (i = 0; i < 32; ++i) {
   2065         //            e[2 * i + 0] = (a[i] >> 0) & 15;
   2066         //            e[2 * i + 1] = (a[i] >> 4) & 15;
   2067         //        }
   2068         for ($i = 0; $i < 32; ++$i) {
   2069             $e[($i << 1)    ] =  self::chrToInt($a[$i]) & 15;
   2070             $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15;
   2071         }
   2072         //        /* each e[i] is between 0 and 15 */
   2073         //        /* e[63] is between 0 and 7 */
   2074 
   2075         //        carry = 0;
   2076         //        for (i = 0; i < 63; ++i) {
   2077         //            e[i] += carry;
   2078         //            carry = e[i] + 8;
   2079         //            carry >>= 4;
   2080         //            e[i] -= carry * ((signed char) 1 << 4);
   2081         //        }
   2082         $carry = 0;
   2083         for ($i = 0; $i < 64; ++$i) {
   2084             $e[$i] += $carry;
   2085             $carry = $e[$i] + 8;
   2086             $carry >>= 4;
   2087             $e[$i] -= $carry << 4;
   2088         }
   2089         //        e[63] += carry;
   2090         //        /* each e[i] is between -8 and 8 */
   2091         $e[63] += $carry;
   2092 
   2093         //        ge25519_p3_0(h);
   2094         $h = self::ge_p3_0();
   2095 
   2096         //        for (i = 63; i != 0; i--) {
   2097         for ($i = 63; $i != 0; --$i) {
   2098             // ge25519_cmov8_cached(&t, pi, e[i]);
   2099             $t = self::ge_cmov8_cached($pi, $e[$i]);
   2100             // ge25519_add_cached(&r, h, &t);
   2101             $r = self::ge_add($h, $t);
   2102 
   2103             // ge25519_p1p1_to_p2(&s, &r);
   2104             // ge25519_p2_dbl(&r, &s);
   2105             // ge25519_p1p1_to_p2(&s, &r);
   2106             // ge25519_p2_dbl(&r, &s);
   2107             // ge25519_p1p1_to_p2(&s, &r);
   2108             // ge25519_p2_dbl(&r, &s);
   2109             // ge25519_p1p1_to_p2(&s, &r);
   2110             // ge25519_p2_dbl(&r, &s);
   2111             $s = self::ge_p1p1_to_p2($r);
   2112             $r = self::ge_p2_dbl($s);
   2113             $s = self::ge_p1p1_to_p2($r);
   2114             $r = self::ge_p2_dbl($s);
   2115             $s = self::ge_p1p1_to_p2($r);
   2116             $r = self::ge_p2_dbl($s);
   2117             $s = self::ge_p1p1_to_p2($r);
   2118             $r = self::ge_p2_dbl($s);
   2119 
   2120             // ge25519_p1p1_to_p3(h, &r);  /* *16 */
   2121             $h = self::ge_p1p1_to_p3($r); /* *16 */
   2122         }
   2123 
   2124         //        ge25519_cmov8_cached(&t, pi, e[i]);
   2125         //        ge25519_add_cached(&r, h, &t);
   2126         //        ge25519_p1p1_to_p3(h, &r);
   2127         $t = self::ge_cmov8_cached($pi, $e[0]);
   2128         $r = self::ge_add($h, $t);
   2129         return self::ge_p1p1_to_p3($r);
   2130     }
   2131 
   2132     /**
   2133      * @internal You should not use this directly from another application
   2134      *
   2135      * @param string $a
   2136      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
   2137      * @throws SodiumException
   2138      * @throws TypeError
   2139      * @psalm-suppress MixedAssignment
   2140      * @psalm-suppress MixedOperand
   2141      */
   2142     public static function ge_scalarmult_base($a)
   2143     {
   2144         /** @var array<int, int> $e */
   2145         $e = array();
   2146         $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
   2147 
   2148         for ($i = 0; $i < 32; ++$i) {
   2149             /** @var int $dbl */
   2150             $dbl = (int) $i << 1;
   2151             $e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
   2152             $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
   2153         }
   2154 
   2155         /** @var int $carry */
   2156         $carry = 0;
   2157         for ($i = 0; $i < 63; ++$i) {
   2158             $e[$i] += $carry;
   2159             /** @var int $carry */
   2160             $carry = $e[$i] + 8;
   2161             /** @var int $carry */
   2162             $carry >>= 4;
   2163             $e[$i] -= $carry << 4;
   2164         }
   2165         /** @var array<int, int> $e */
   2166         $e[63] += (int) $carry;
   2167 
   2168         $h = self::ge_p3_0();
   2169 
   2170         for ($i = 1; $i < 64; $i += 2) {
   2171             $t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
   2172             $r = self::ge_madd($r, $h, $t);
   2173             $h = self::ge_p1p1_to_p3($r);
   2174         }
   2175 
   2176         $r = self::ge_p3_dbl($h);
   2177 
   2178         $s = self::ge_p1p1_to_p2($r);
   2179         $r = self::ge_p2_dbl($s);
   2180         $s = self::ge_p1p1_to_p2($r);
   2181         $r = self::ge_p2_dbl($s);
   2182         $s = self::ge_p1p1_to_p2($r);
   2183         $r = self::ge_p2_dbl($s);
   2184 
   2185         $h = self::ge_p1p1_to_p3($r);
   2186 
   2187         for ($i = 0; $i < 64; $i += 2) {
   2188             $t = self::ge_select($i >> 1, (int) $e[$i]);
   2189             $r = self::ge_madd($r, $h, $t);
   2190             $h = self::ge_p1p1_to_p3($r);
   2191         }
   2192         return $h;
   2193     }
   2194 
   2195     /**
   2196      * Calculates (ab + c) mod l
   2197      * where l = 2^252 + 27742317777372353535851937790883648493
   2198      *
   2199      * @internal You should not use this directly from another application
   2200      *
   2201      * @param string $a
   2202      * @param string $b
   2203      * @param string $c
   2204      * @return string
   2205      * @throws TypeError
   2206      */
   2207     public static function sc_muladd($a, $b, $c)
   2208     {
   2209         /** @var int $a0 */
   2210         $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
   2211         /** @var int $a1 */
   2212         $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
   2213         /** @var int $a2 */
   2214         $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
   2215         /** @var int $a3 */
   2216         $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
   2217         /** @var int $a4 */
   2218         $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
   2219         /** @var int $a5 */
   2220         $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
   2221         /** @var int $a6 */
   2222         $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
   2223         /** @var int $a7 */
   2224         $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
   2225         /** @var int $a8 */
   2226         $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
   2227         /** @var int $a9 */
   2228         $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
   2229         /** @var int $a10 */
   2230         $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
   2231         /** @var int $a11 */
   2232         $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
   2233 
   2234         /** @var int $b0 */
   2235         $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
   2236         /** @var int $b1 */
   2237         $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
   2238         /** @var int $b2 */
   2239         $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
   2240         /** @var int $b3 */
   2241         $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
   2242         /** @var int $b4 */
   2243         $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
   2244         /** @var int $b5 */
   2245         $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
   2246         /** @var int $b6 */
   2247         $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
   2248         /** @var int $b7 */
   2249         $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
   2250         /** @var int $b8 */
   2251         $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
   2252         /** @var int $b9 */
   2253         $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
   2254         /** @var int $b10 */
   2255         $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
   2256         /** @var int $b11 */
   2257         $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
   2258 
   2259         /** @var int $c0 */
   2260         $c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
   2261         /** @var int $c1 */
   2262         $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5);
   2263         /** @var int $c2 */
   2264         $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2);
   2265         /** @var int $c3 */
   2266         $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7);
   2267         /** @var int $c4 */
   2268         $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4);
   2269         /** @var int $c5 */
   2270         $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1);
   2271         /** @var int $c6 */
   2272         $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6);
   2273         /** @var int $c7 */
   2274         $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3);
   2275         /** @var int $c8 */
   2276         $c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
   2277         /** @var int $c9 */
   2278         $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5);
   2279         /** @var int $c10 */
   2280         $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2);
   2281         /** @var int $c11 */
   2282         $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);
   2283 
   2284         /* Can't really avoid the pyramid here: */
   2285         $s0 = $c0 + self::mul($a0, $b0, 24);
   2286         $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
   2287         $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24);
   2288         $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
   2289         $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
   2290                self::mul($a4, $b0, 24);
   2291         $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
   2292                self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
   2293         $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
   2294                self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24);
   2295         $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
   2296                self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
   2297         $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
   2298                self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
   2299                self::mul($a8, $b0, 24);
   2300         $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
   2301                self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
   2302                self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
   2303         $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
   2304                self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
   2305                self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24);
   2306         $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
   2307                self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
   2308                self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
   2309         $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
   2310                self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
   2311                self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24);
   2312         $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
   2313                self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
   2314                self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
   2315         $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
   2316                self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
   2317                self::mul($a11, $b3, 24);
   2318         $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
   2319                self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
   2320         $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
   2321                self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24);
   2322         $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
   2323                self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
   2324         $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
   2325                self::mul($a11, $b7, 24);
   2326         $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
   2327         $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24);
   2328         $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
   2329         $s22 = self::mul($a11, $b11, 24);
   2330         $s23 = 0;
   2331 
   2332         /** @var int $carry0 */
   2333         $carry0 = ($s0 + (1 << 20)) >> 21;
   2334         $s1 += $carry0;
   2335         $s0 -= $carry0 << 21;
   2336         /** @var int $carry2 */
   2337         $carry2 = ($s2 + (1 << 20)) >> 21;
   2338         $s3 += $carry2;
   2339         $s2 -= $carry2 << 21;
   2340         /** @var int $carry4 */
   2341         $carry4 = ($s4 + (1 << 20)) >> 21;
   2342         $s5 += $carry4;
   2343         $s4 -= $carry4 << 21;
   2344         /** @var int $carry6 */
   2345         $carry6 = ($s6 + (1 << 20)) >> 21;
   2346         $s7 += $carry6;
   2347         $s6 -= $carry6 << 21;
   2348         /** @var int $carry8 */
   2349         $carry8 = ($s8 + (1 << 20)) >> 21;
   2350         $s9 += $carry8;
   2351         $s8 -= $carry8 << 21;
   2352         /** @var int $carry10 */
   2353         $carry10 = ($s10 + (1 << 20)) >> 21;
   2354         $s11 += $carry10;
   2355         $s10 -= $carry10 << 21;
   2356         /** @var int $carry12 */
   2357         $carry12 = ($s12 + (1 << 20)) >> 21;
   2358         $s13 += $carry12;
   2359         $s12 -= $carry12 << 21;
   2360         /** @var int $carry14 */
   2361         $carry14 = ($s14 + (1 << 20)) >> 21;
   2362         $s15 += $carry14;
   2363         $s14 -= $carry14 << 21;
   2364         /** @var int $carry16 */
   2365         $carry16 = ($s16 + (1 << 20)) >> 21;
   2366         $s17 += $carry16;
   2367         $s16 -= $carry16 << 21;
   2368         /** @var int $carry18 */
   2369         $carry18 = ($s18 + (1 << 20)) >> 21;
   2370         $s19 += $carry18;
   2371         $s18 -= $carry18 << 21;
   2372         /** @var int $carry20 */
   2373         $carry20 = ($s20 + (1 << 20)) >> 21;
   2374         $s21 += $carry20;
   2375         $s20 -= $carry20 << 21;
   2376         /** @var int $carry22 */
   2377         $carry22 = ($s22 + (1 << 20)) >> 21;
   2378         $s23 += $carry22;
   2379         $s22 -= $carry22 << 21;
   2380 
   2381         /** @var int $carry1 */
   2382         $carry1 = ($s1 + (1 << 20)) >> 21;
   2383         $s2 += $carry1;
   2384         $s1 -= $carry1 << 21;
   2385         /** @var int $carry3 */
   2386         $carry3 = ($s3 + (1 << 20)) >> 21;
   2387         $s4 += $carry3;
   2388         $s3 -= $carry3 << 21;
   2389         /** @var int $carry5 */
   2390         $carry5 = ($s5 + (1 << 20)) >> 21;
   2391         $s6 += $carry5;
   2392         $s5 -= $carry5 << 21;
   2393         /** @var int $carry7 */
   2394         $carry7 = ($s7 + (1 << 20)) >> 21;
   2395         $s8 += $carry7;
   2396         $s7 -= $carry7 << 21;
   2397         /** @var int $carry9 */
   2398         $carry9 = ($s9 + (1 << 20)) >> 21;
   2399         $s10 += $carry9;
   2400         $s9 -= $carry9 << 21;
   2401         /** @var int $carry11 */
   2402         $carry11 = ($s11 + (1 << 20)) >> 21;
   2403         $s12 += $carry11;
   2404         $s11 -= $carry11 << 21;
   2405         /** @var int $carry13 */
   2406         $carry13 = ($s13 + (1 << 20)) >> 21;
   2407         $s14 += $carry13;
   2408         $s13 -= $carry13 << 21;
   2409         /** @var int $carry15 */
   2410         $carry15 = ($s15 + (1 << 20)) >> 21;
   2411         $s16 += $carry15;
   2412         $s15 -= $carry15 << 21;
   2413         /** @var int $carry17 */
   2414         $carry17 = ($s17 + (1 << 20)) >> 21;
   2415         $s18 += $carry17;
   2416         $s17 -= $carry17 << 21;
   2417         /** @var int $carry19 */
   2418         $carry19 = ($s19 + (1 << 20)) >> 21;
   2419         $s20 += $carry19;
   2420         $s19 -= $carry19 << 21;
   2421         /** @var int $carry21 */
   2422         $carry21 = ($s21 + (1 << 20)) >> 21;
   2423         $s22 += $carry21;
   2424         $s21 -= $carry21 << 21;
   2425 
   2426         $s11 += self::mul($s23, 666643, 20);
   2427         $s12 += self::mul($s23, 470296, 19);
   2428         $s13 += self::mul($s23, 654183, 20);
   2429         $s14 -= self::mul($s23, 997805, 20);
   2430         $s15 += self::mul($s23, 136657, 18);
   2431         $s16 -= self::mul($s23, 683901, 20);
   2432 
   2433         $s10 += self::mul($s22, 666643, 20);
   2434         $s11 += self::mul($s22, 470296, 19);
   2435         $s12 += self::mul($s22, 654183, 20);
   2436         $s13 -= self::mul($s22, 997805, 20);
   2437         $s14 += self::mul($s22, 136657, 18);
   2438         $s15 -= self::mul($s22, 683901, 20);
   2439 
   2440         $s9  += self::mul($s21,  666643, 20);
   2441         $s10 += self::mul($s21,  470296, 19);
   2442         $s11 += self::mul($s21,  654183, 20);
   2443         $s12 -= self::mul($s21,  997805, 20);
   2444         $s13 += self::mul($s21,  136657, 18);
   2445         $s14 -= self::mul($s21,  683901, 20);
   2446 
   2447         $s8  += self::mul($s20,  666643, 20);
   2448         $s9  += self::mul($s20,  470296, 19);
   2449         $s10 += self::mul($s20,  654183, 20);
   2450         $s11 -= self::mul($s20,  997805, 20);
   2451         $s12 += self::mul($s20,  136657, 18);
   2452         $s13 -= self::mul($s20,  683901, 20);
   2453 
   2454         $s7  += self::mul($s19,  666643, 20);
   2455         $s8  += self::mul($s19,  470296, 19);
   2456         $s9  += self::mul($s19,  654183, 20);
   2457         $s10 -= self::mul($s19,  997805, 20);
   2458         $s11 += self::mul($s19,  136657, 18);
   2459         $s12 -= self::mul($s19,  683901, 20);
   2460 
   2461         $s6  += self::mul($s18,  666643, 20);
   2462         $s7  += self::mul($s18,  470296, 19);
   2463         $s8  += self::mul($s18,  654183, 20);
   2464         $s9  -= self::mul($s18,  997805, 20);
   2465         $s10 += self::mul($s18,  136657, 18);
   2466         $s11 -= self::mul($s18,  683901, 20);
   2467 
   2468         /** @var int $carry6 */
   2469         $carry6 = ($s6 + (1 << 20)) >> 21;
   2470         $s7 += $carry6;
   2471         $s6 -= $carry6 << 21;
   2472         /** @var int $carry8 */
   2473         $carry8 = ($s8 + (1 << 20)) >> 21;
   2474         $s9 += $carry8;
   2475         $s8 -= $carry8 << 21;
   2476         /** @var int $carry10 */
   2477         $carry10 = ($s10 + (1 << 20)) >> 21;
   2478         $s11 += $carry10;
   2479         $s10 -= $carry10 << 21;
   2480         /** @var int $carry12 */
   2481         $carry12 = ($s12 + (1 << 20)) >> 21;
   2482         $s13 += $carry12;
   2483         $s12 -= $carry12 << 21;
   2484         /** @var int $carry14 */
   2485         $carry14 = ($s14 + (1 << 20)) >> 21;
   2486         $s15 += $carry14;
   2487         $s14 -= $carry14 << 21;
   2488         /** @var int $carry16 */
   2489         $carry16 = ($s16 + (1 << 20)) >> 21;
   2490         $s17 += $carry16;
   2491         $s16 -= $carry16 << 21;
   2492 
   2493         /** @var int $carry7 */
   2494         $carry7 = ($s7 + (1 << 20)) >> 21;
   2495         $s8 += $carry7;
   2496         $s7 -= $carry7 << 21;
   2497         /** @var int $carry9 */
   2498         $carry9 = ($s9 + (1 << 20)) >> 21;
   2499         $s10 += $carry9;
   2500         $s9 -= $carry9 << 21;
   2501         /** @var int $carry11 */
   2502         $carry11 = ($s11 + (1 << 20)) >> 21;
   2503         $s12 += $carry11;
   2504         $s11 -= $carry11 << 21;
   2505         /** @var int $carry13 */
   2506         $carry13 = ($s13 + (1 << 20)) >> 21;
   2507         $s14 += $carry13;
   2508         $s13 -= $carry13 << 21;
   2509         /** @var int $carry15 */
   2510         $carry15 = ($s15 + (1 << 20)) >> 21;
   2511         $s16 += $carry15;
   2512         $s15 -= $carry15 << 21;
   2513 
   2514         $s5  += self::mul($s17,  666643, 20);
   2515         $s6  += self::mul($s17,  470296, 19);
   2516         $s7  += self::mul($s17,  654183, 20);
   2517         $s8  -= self::mul($s17,  997805, 20);
   2518         $s9  += self::mul($s17,  136657, 18);
   2519         $s10 -= self::mul($s17,  683901, 20);
   2520 
   2521         $s4 += self::mul($s16,  666643, 20);
   2522         $s5 += self::mul($s16,  470296, 19);
   2523         $s6 += self::mul($s16,  654183, 20);
   2524         $s7 -= self::mul($s16,  997805, 20);
   2525         $s8 += self::mul($s16,  136657, 18);
   2526         $s9 -= self::mul($s16,  683901, 20);
   2527 
   2528         $s3 += self::mul($s15,  666643, 20);
   2529         $s4 += self::mul($s15,  470296, 19);
   2530         $s5 += self::mul($s15,  654183, 20);
   2531         $s6 -= self::mul($s15,  997805, 20);
   2532         $s7 += self::mul($s15,  136657, 18);
   2533         $s8 -= self::mul($s15,  683901, 20);
   2534 
   2535         $s2 += self::mul($s14,  666643, 20);
   2536         $s3 += self::mul($s14,  470296, 19);
   2537         $s4 += self::mul($s14,  654183, 20);
   2538         $s5 -= self::mul($s14,  997805, 20);
   2539         $s6 += self::mul($s14,  136657, 18);
   2540         $s7 -= self::mul($s14,  683901, 20);
   2541 
   2542         $s1 += self::mul($s13,  666643, 20);
   2543         $s2 += self::mul($s13,  470296, 19);
   2544         $s3 += self::mul($s13,  654183, 20);
   2545         $s4 -= self::mul($s13,  997805, 20);
   2546         $s5 += self::mul($s13,  136657, 18);
   2547         $s6 -= self::mul($s13,  683901, 20);
   2548 
   2549         $s0 += self::mul($s12,  666643, 20);
   2550         $s1 += self::mul($s12,  470296, 19);
   2551         $s2 += self::mul($s12,  654183, 20);
   2552         $s3 -= self::mul($s12,  997805, 20);
   2553         $s4 += self::mul($s12,  136657, 18);
   2554         $s5 -= self::mul($s12,  683901, 20);
   2555         $s12 = 0;
   2556 
   2557         /** @var int $carry0 */
   2558         $carry0 = ($s0 + (1 << 20)) >> 21;
   2559         $s1 += $carry0;
   2560         $s0 -= $carry0 << 21;
   2561         /** @var int $carry2 */
   2562         $carry2 = ($s2 + (1 << 20)) >> 21;
   2563         $s3 += $carry2;
   2564         $s2 -= $carry2 << 21;
   2565         /** @var int $carry4 */
   2566         $carry4 = ($s4 + (1 << 20)) >> 21;
   2567         $s5 += $carry4;
   2568         $s4 -= $carry4 << 21;
   2569         /** @var int $carry6 */
   2570         $carry6 = ($s6 + (1 << 20)) >> 21;
   2571         $s7 += $carry6;
   2572         $s6 -= $carry6 << 21;
   2573         /** @var int $carry8 */
   2574         $carry8 = ($s8 + (1 << 20)) >> 21;
   2575         $s9 += $carry8;
   2576         $s8 -= $carry8 << 21;
   2577         /** @var int $carry10 */
   2578         $carry10 = ($s10 + (1 << 20)) >> 21;
   2579         $s11 += $carry10;
   2580         $s10 -= $carry10 << 21;
   2581 
   2582         /** @var int $carry1 */
   2583         $carry1 = ($s1 + (1 << 20)) >> 21;
   2584         $s2 += $carry1;
   2585         $s1 -= $carry1 << 21;
   2586         /** @var int $carry3 */
   2587         $carry3 = ($s3 + (1 << 20)) >> 21;
   2588         $s4 += $carry3;
   2589         $s3 -= $carry3 << 21;
   2590         /** @var int $carry5 */
   2591         $carry5 = ($s5 + (1 << 20)) >> 21;
   2592         $s6 += $carry5;
   2593         $s5 -= $carry5 << 21;
   2594         /** @var int $carry7 */
   2595         $carry7 = ($s7 + (1 << 20)) >> 21;
   2596         $s8 += $carry7;
   2597         $s7 -= $carry7 << 21;
   2598         /** @var int $carry9 */
   2599         $carry9 = ($s9 + (1 << 20)) >> 21;
   2600         $s10 += $carry9;
   2601         $s9 -= $carry9 << 21;
   2602         /** @var int $carry11 */
   2603         $carry11 = ($s11 + (1 << 20)) >> 21;
   2604         $s12 += $carry11;
   2605         $s11 -= $carry11 << 21;
   2606 
   2607         $s0 += self::mul($s12,  666643, 20);
   2608         $s1 += self::mul($s12,  470296, 19);
   2609         $s2 += self::mul($s12,  654183, 20);
   2610         $s3 -= self::mul($s12,  997805, 20);
   2611         $s4 += self::mul($s12,  136657, 18);
   2612         $s5 -= self::mul($s12,  683901, 20);
   2613         $s12 = 0;
   2614 
   2615         /** @var int $carry0 */
   2616         $carry0 = $s0 >> 21;
   2617         $s1 += $carry0;
   2618         $s0 -= $carry0 << 21;
   2619         /** @var int $carry1 */
   2620         $carry1 = $s1 >> 21;
   2621         $s2 += $carry1;
   2622         $s1 -= $carry1 << 21;
   2623         /** @var int $carry2 */
   2624         $carry2 = $s2 >> 21;
   2625         $s3 += $carry2;
   2626         $s2 -= $carry2 << 21;
   2627         /** @var int $carry3 */
   2628         $carry3 = $s3 >> 21;
   2629         $s4 += $carry3;
   2630         $s3 -= $carry3 << 21;
   2631         /** @var int $carry4 */
   2632         $carry4 = $s4 >> 21;
   2633         $s5 += $carry4;
   2634         $s4 -= $carry4 << 21;
   2635         /** @var int $carry5 */
   2636         $carry5 = $s5 >> 21;
   2637         $s6 += $carry5;
   2638         $s5 -= $carry5 << 21;
   2639         /** @var int $carry6 */
   2640         $carry6 = $s6 >> 21;
   2641         $s7 += $carry6;
   2642         $s6 -= $carry6 << 21;
   2643         /** @var int $carry7 */
   2644         $carry7 = $s7 >> 21;
   2645         $s8 += $carry7;
   2646         $s7 -= $carry7 << 21;
   2647         /** @var int $carry8 */
   2648         $carry8 = $s8 >> 21;
   2649         $s9 += $carry8;
   2650         $s8 -= $carry8 << 21;
   2651         /** @var int $carry9 */
   2652         $carry9 = $s9 >> 21;
   2653         $s10 += $carry9;
   2654         $s9 -= $carry9 << 21;
   2655         /** @var int $carry10 */
   2656         $carry10 = $s10 >> 21;
   2657         $s11 += $carry10;
   2658         $s10 -= $carry10 << 21;
   2659         /** @var int $carry11 */
   2660         $carry11 = $s11 >> 21;
   2661         $s12 += $carry11;
   2662         $s11 -= $carry11 << 21;
   2663 
   2664         $s0 += self::mul($s12,  666643, 20);
   2665         $s1 += self::mul($s12,  470296, 19);
   2666         $s2 += self::mul($s12,  654183, 20);
   2667         $s3 -= self::mul($s12,  997805, 20);
   2668         $s4 += self::mul($s12,  136657, 18);
   2669         $s5 -= self::mul($s12,  683901, 20);
   2670 
   2671         /** @var int $carry0 */
   2672         $carry0 = $s0 >> 21;
   2673         $s1 += $carry0;
   2674         $s0 -= $carry0 << 21;
   2675         /** @var int $carry1 */
   2676         $carry1 = $s1 >> 21;
   2677         $s2 += $carry1;
   2678         $s1 -= $carry1 << 21;
   2679         /** @var int $carry2 */
   2680         $carry2 = $s2 >> 21;
   2681         $s3 += $carry2;
   2682         $s2 -= $carry2 << 21;
   2683         /** @var int $carry3 */
   2684         $carry3 = $s3 >> 21;
   2685         $s4 += $carry3;
   2686         $s3 -= $carry3 << 21;
   2687         /** @var int $carry4 */
   2688         $carry4 = $s4 >> 21;
   2689         $s5 += $carry4;
   2690         $s4 -= $carry4 << 21;
   2691         /** @var int $carry5 */
   2692         $carry5 = $s5 >> 21;
   2693         $s6 += $carry5;
   2694         $s5 -= $carry5 << 21;
   2695         /** @var int $carry6 */
   2696         $carry6 = $s6 >> 21;
   2697         $s7 += $carry6;
   2698         $s6 -= $carry6 << 21;
   2699         /** @var int $carry7 */
   2700         $carry7 = $s7 >> 21;
   2701         $s8 += $carry7;
   2702         $s7 -= $carry7 << 21;
   2703         /** @var int $carry8 */
   2704         $carry8 = $s8 >> 21;
   2705         $s9 += $carry8;
   2706         $s8 -= $carry8 << 21;
   2707         /** @var int $carry9 */
   2708         $carry9 = $s9 >> 21;
   2709         $s10 += $carry9;
   2710         $s9 -= $carry9 << 21;
   2711         /** @var int $carry10 */
   2712         $carry10 = $s10 >> 21;
   2713         $s11 += $carry10;
   2714         $s10 -= $carry10 << 21;
   2715 
   2716         /**
   2717          * @var array<int, int>
   2718          */
   2719         $arr = array(
   2720             (int) (0xff & ($s0 >> 0)),
   2721             (int) (0xff & ($s0 >> 8)),
   2722             (int) (0xff & (($s0 >> 16) | $s1 << 5)),
   2723             (int) (0xff & ($s1 >> 3)),
   2724             (int) (0xff & ($s1 >> 11)),
   2725             (int) (0xff & (($s1 >> 19) | $s2 << 2)),
   2726             (int) (0xff & ($s2 >> 6)),
   2727             (int) (0xff & (($s2 >> 14) | $s3 << 7)),
   2728             (int) (0xff & ($s3 >> 1)),
   2729             (int) (0xff & ($s3 >> 9)),
   2730             (int) (0xff & (($s3 >> 17) | $s4 << 4)),
   2731             (int) (0xff & ($s4 >> 4)),
   2732             (int) (0xff & ($s4 >> 12)),
   2733             (int) (0xff & (($s4 >> 20) | $s5 << 1)),
   2734             (int) (0xff & ($s5 >> 7)),
   2735             (int) (0xff & (($s5 >> 15) | $s6 << 6)),
   2736             (int) (0xff & ($s6 >> 2)),
   2737             (int) (0xff & ($s6 >> 10)),
   2738             (int) (0xff & (($s6 >> 18) | $s7 << 3)),
   2739             (int) (0xff & ($s7 >> 5)),
   2740             (int) (0xff & ($s7 >> 13)),
   2741             (int) (0xff & ($s8 >> 0)),
   2742             (int) (0xff & ($s8 >> 8)),
   2743             (int) (0xff & (($s8 >> 16) | $s9 << 5)),
   2744             (int) (0xff & ($s9 >> 3)),
   2745             (int) (0xff & ($s9 >> 11)),
   2746             (int) (0xff & (($s9 >> 19) | $s10 << 2)),
   2747             (int) (0xff & ($s10 >> 6)),
   2748             (int) (0xff & (($s10 >> 14) | $s11 << 7)),
   2749             (int) (0xff & ($s11 >> 1)),
   2750             (int) (0xff & ($s11 >> 9)),
   2751             0xff & ($s11 >> 17)
   2752         );
   2753         return self::intArrayToString($arr);
   2754     }
   2755 
   2756     /**
   2757      * @internal You should not use this directly from another application
   2758      *
   2759      * @param string $s
   2760      * @return string
   2761      * @throws TypeError
   2762      */
   2763     public static function sc_reduce($s)
   2764     {
   2765         /** @var int $s0 */
   2766         $s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
   2767         /** @var int $s1 */
   2768         $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5);
   2769         /** @var int $s2 */
   2770         $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2);
   2771         /** @var int $s3 */
   2772         $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7);
   2773         /** @var int $s4 */
   2774         $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4);
   2775         /** @var int $s5 */
   2776         $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1);
   2777         /** @var int $s6 */
   2778         $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6);
   2779         /** @var int $s7 */
   2780         $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3);
   2781         /** @var int $s8 */
   2782         $s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
   2783         /** @var int $s9 */
   2784         $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5);
   2785         /** @var int $s10 */
   2786         $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2);
   2787         /** @var int $s11 */
   2788         $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7);
   2789         /** @var int $s12 */
   2790         $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4);
   2791         /** @var int $s13 */
   2792         $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1);
   2793         /** @var int $s14 */
   2794         $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6);
   2795         /** @var int $s15 */
   2796         $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3);
   2797         /** @var int $s16 */
   2798         $s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
   2799         /** @var int $s17 */
   2800         $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5);
   2801         /** @var int $s18 */
   2802         $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2);
   2803         /** @var int $s19 */
   2804         $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7);
   2805         /** @var int $s20 */
   2806         $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4);
   2807         /** @var int $s21 */
   2808         $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1);
   2809         /** @var int $s22 */
   2810         $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6);
   2811         /** @var int $s23 */
   2812         $s23 = (self::load_4(self::substr($s, 60, 4)) >> 3);
   2813 
   2814         $s11 += self::mul($s23,  666643, 20);
   2815         $s12 += self::mul($s23,  470296, 19);
   2816         $s13 += self::mul($s23,  654183, 20);
   2817         $s14 -= self::mul($s23,  997805, 20);
   2818         $s15 += self::mul($s23,  136657, 18);
   2819         $s16 -= self::mul($s23,  683901, 20);
   2820 
   2821         $s10 += self::mul($s22,  666643, 20);
   2822         $s11 += self::mul($s22,  470296, 19);
   2823         $s12 += self::mul($s22,  654183, 20);
   2824         $s13 -= self::mul($s22,  997805, 20);
   2825         $s14 += self::mul($s22,  136657, 18);
   2826         $s15 -= self::mul($s22,  683901, 20);
   2827 
   2828         $s9  += self::mul($s21,  666643, 20);
   2829         $s10 += self::mul($s21,  470296, 19);
   2830         $s11 += self::mul($s21,  654183, 20);
   2831         $s12 -= self::mul($s21,  997805, 20);
   2832         $s13 += self::mul($s21,  136657, 18);
   2833         $s14 -= self::mul($s21,  683901, 20);
   2834 
   2835         $s8  += self::mul($s20,  666643, 20);
   2836         $s9  += self::mul($s20,  470296, 19);
   2837         $s10 += self::mul($s20,  654183, 20);
   2838         $s11 -= self::mul($s20,  997805, 20);
   2839         $s12 += self::mul($s20,  136657, 18);
   2840         $s13 -= self::mul($s20,  683901, 20);
   2841 
   2842         $s7  += self::mul($s19,  666643, 20);
   2843         $s8  += self::mul($s19,  470296, 19);
   2844         $s9  += self::mul($s19,  654183, 20);
   2845         $s10 -= self::mul($s19,  997805, 20);
   2846         $s11 += self::mul($s19,  136657, 18);
   2847         $s12 -= self::mul($s19,  683901, 20);
   2848 
   2849         $s6  += self::mul($s18,  666643, 20);
   2850         $s7  += self::mul($s18,  470296, 19);
   2851         $s8  += self::mul($s18,  654183, 20);
   2852         $s9  -= self::mul($s18,  997805, 20);
   2853         $s10 += self::mul($s18,  136657, 18);
   2854         $s11 -= self::mul($s18,  683901, 20);
   2855 
   2856         /** @var int $carry6 */
   2857         $carry6 = ($s6 + (1 << 20)) >> 21;
   2858         $s7 += $carry6;
   2859         $s6 -= $carry6 << 21;
   2860         /** @var int $carry8 */
   2861         $carry8 = ($s8 + (1 << 20)) >> 21;
   2862         $s9 += $carry8;
   2863         $s8 -= $carry8 << 21;
   2864         /** @var int $carry10 */
   2865         $carry10 = ($s10 + (1 << 20)) >> 21;
   2866         $s11 += $carry10;
   2867         $s10 -= $carry10 << 21;
   2868         /** @var int $carry12 */
   2869         $carry12 = ($s12 + (1 << 20)) >> 21;
   2870         $s13 += $carry12;
   2871         $s12 -= $carry12 << 21;
   2872         /** @var int $carry14 */
   2873         $carry14 = ($s14 + (1 << 20)) >> 21;
   2874         $s15 += $carry14;
   2875         $s14 -= $carry14 << 21;
   2876         /** @var int $carry16 */
   2877         $carry16 = ($s16 + (1 << 20)) >> 21;
   2878         $s17 += $carry16;
   2879         $s16 -= $carry16 << 21;
   2880 
   2881         /** @var int $carry7 */
   2882         $carry7 = ($s7 + (1 << 20)) >> 21;
   2883         $s8 += $carry7;
   2884         $s7 -= $carry7 << 21;
   2885         /** @var int $carry9 */
   2886         $carry9 = ($s9 + (1 << 20)) >> 21;
   2887         $s10 += $carry9;
   2888         $s9 -= $carry9 << 21;
   2889         /** @var int $carry11 */
   2890         $carry11 = ($s11 + (1 << 20)) >> 21;
   2891         $s12 += $carry11;
   2892         $s11 -= $carry11 << 21;
   2893         /** @var int $carry13 */
   2894         $carry13 = ($s13 + (1 << 20)) >> 21;
   2895         $s14 += $carry13;
   2896         $s13 -= $carry13 << 21;
   2897         /** @var int $carry15 */
   2898         $carry15 = ($s15 + (1 << 20)) >> 21;
   2899         $s16 += $carry15;
   2900         $s15 -= $carry15 << 21;
   2901 
   2902         $s5  += self::mul($s17,  666643, 20);
   2903         $s6  += self::mul($s17,  470296, 19);
   2904         $s7  += self::mul($s17,  654183, 20);
   2905         $s8  -= self::mul($s17,  997805, 20);
   2906         $s9  += self::mul($s17,  136657, 18);
   2907         $s10 -= self::mul($s17,  683901, 20);
   2908 
   2909         $s4 += self::mul($s16,  666643, 20);
   2910         $s5 += self::mul($s16,  470296, 19);
   2911         $s6 += self::mul($s16,  654183, 20);
   2912         $s7 -= self::mul($s16,  997805, 20);
   2913         $s8 += self::mul($s16,  136657, 18);
   2914         $s9 -= self::mul($s16,  683901, 20);
   2915 
   2916         $s3 += self::mul($s15,  666643, 20);
   2917         $s4 += self::mul($s15,  470296, 19);
   2918         $s5 += self::mul($s15,  654183, 20);
   2919         $s6 -= self::mul($s15,  997805, 20);
   2920         $s7 += self::mul($s15,  136657, 18);
   2921         $s8 -= self::mul($s15,  683901, 20);
   2922 
   2923         $s2 += self::mul($s14,  666643, 20);
   2924         $s3 += self::mul($s14,  470296, 19);
   2925         $s4 += self::mul($s14,  654183, 20);
   2926         $s5 -= self::mul($s14,  997805, 20);
   2927         $s6 += self::mul($s14,  136657, 18);
   2928         $s7 -= self::mul($s14,  683901, 20);
   2929 
   2930         $s1 += self::mul($s13,  666643, 20);
   2931         $s2 += self::mul($s13,  470296, 19);
   2932         $s3 += self::mul($s13,  654183, 20);
   2933         $s4 -= self::mul($s13,  997805, 20);
   2934         $s5 += self::mul($s13,  136657, 18);
   2935         $s6 -= self::mul($s13,  683901, 20);
   2936 
   2937         $s0 += self::mul($s12,  666643, 20);
   2938         $s1 += self::mul($s12,  470296, 19);
   2939         $s2 += self::mul($s12,  654183, 20);
   2940         $s3 -= self::mul($s12,  997805, 20);
   2941         $s4 += self::mul($s12,  136657, 18);
   2942         $s5 -= self::mul($s12,  683901, 20);
   2943         $s12 = 0;
   2944 
   2945         /** @var int $carry0 */
   2946         $carry0 = ($s0 + (1 << 20)) >> 21;
   2947         $s1 += $carry0;
   2948         $s0 -= $carry0 << 21;
   2949         /** @var int $carry2 */
   2950         $carry2 = ($s2 + (1 << 20)) >> 21;
   2951         $s3 += $carry2;
   2952         $s2 -= $carry2 << 21;
   2953         /** @var int $carry4 */
   2954         $carry4 = ($s4 + (1 << 20)) >> 21;
   2955         $s5 += $carry4;
   2956         $s4 -= $carry4 << 21;
   2957         /** @var int $carry6 */
   2958         $carry6 = ($s6 + (1 << 20)) >> 21;
   2959         $s7 += $carry6;
   2960         $s6 -= $carry6 << 21;
   2961         /** @var int $carry8 */
   2962         $carry8 = ($s8 + (1 << 20)) >> 21;
   2963         $s9 += $carry8;
   2964         $s8 -= $carry8 << 21;
   2965         /** @var int $carry10 */
   2966         $carry10 = ($s10 + (1 << 20)) >> 21;
   2967         $s11 += $carry10;
   2968         $s10 -= $carry10 << 21;
   2969 
   2970         /** @var int $carry1 */
   2971         $carry1 = ($s1 + (1 << 20)) >> 21;
   2972         $s2 += $carry1;
   2973         $s1 -= $carry1 << 21;
   2974         /** @var int $carry3 */
   2975         $carry3 = ($s3 + (1 << 20)) >> 21;
   2976         $s4 += $carry3;
   2977         $s3 -= $carry3 << 21;
   2978         /** @var int $carry5 */
   2979         $carry5 = ($s5 + (1 << 20)) >> 21;
   2980         $s6 += $carry5;
   2981         $s5 -= $carry5 << 21;
   2982         /** @var int $carry7 */
   2983         $carry7 = ($s7 + (1 << 20)) >> 21;
   2984         $s8 += $carry7;
   2985         $s7 -= $carry7 << 21;
   2986         /** @var int $carry9 */
   2987         $carry9 = ($s9 + (1 << 20)) >> 21;
   2988         $s10 += $carry9;
   2989         $s9 -= $carry9 << 21;
   2990         /** @var int $carry11 */
   2991         $carry11 = ($s11 + (1 << 20)) >> 21;
   2992         $s12 += $carry11;
   2993         $s11 -= $carry11 << 21;
   2994 
   2995         $s0 += self::mul($s12,  666643, 20);
   2996         $s1 += self::mul($s12,  470296, 19);
   2997         $s2 += self::mul($s12,  654183, 20);
   2998         $s3 -= self::mul($s12,  997805, 20);
   2999         $s4 += self::mul($s12,  136657, 18);
   3000         $s5 -= self::mul($s12,  683901, 20);
   3001         $s12 = 0;
   3002 
   3003         /** @var int $carry0 */
   3004         $carry0 = $s0 >> 21;
   3005         $s1 += $carry0;
   3006         $s0 -= $carry0 << 21;
   3007         /** @var int $carry1 */
   3008         $carry1 = $s1 >> 21;
   3009         $s2 += $carry1;
   3010         $s1 -= $carry1 << 21;
   3011         /** @var int $carry2 */
   3012         $carry2 = $s2 >> 21;
   3013         $s3 += $carry2;
   3014         $s2 -= $carry2 << 21;
   3015         /** @var int $carry3 */
   3016         $carry3 = $s3 >> 21;
   3017         $s4 += $carry3;
   3018         $s3 -= $carry3 << 21;
   3019         /** @var int $carry4 */
   3020         $carry4 = $s4 >> 21;
   3021         $s5 += $carry4;
   3022         $s4 -= $carry4 << 21;
   3023         /** @var int $carry5 */
   3024         $carry5 = $s5 >> 21;
   3025         $s6 += $carry5;
   3026         $s5 -= $carry5 << 21;
   3027         /** @var int $carry6 */
   3028         $carry6 = $s6 >> 21;
   3029         $s7 += $carry6;
   3030         $s6 -= $carry6 << 21;
   3031         /** @var int $carry7 */
   3032         $carry7 = $s7 >> 21;
   3033         $s8 += $carry7;
   3034         $s7 -= $carry7 << 21;
   3035         /** @var int $carry8 */
   3036         $carry8 = $s8 >> 21;
   3037         $s9 += $carry8;
   3038         $s8 -= $carry8 << 21;
   3039         /** @var int $carry9 */
   3040         $carry9 = $s9 >> 21;
   3041         $s10 += $carry9;
   3042         $s9 -= $carry9 << 21;
   3043         /** @var int $carry10 */
   3044         $carry10 = $s10 >> 21;
   3045         $s11 += $carry10;
   3046         $s10 -= $carry10 << 21;
   3047         /** @var int $carry11 */
   3048         $carry11 = $s11 >> 21;
   3049         $s12 += $carry11;
   3050         $s11 -= $carry11 << 21;
   3051 
   3052         $s0 += self::mul($s12,  666643, 20);
   3053         $s1 += self::mul($s12,  470296, 19);
   3054         $s2 += self::mul($s12,  654183, 20);
   3055         $s3 -= self::mul($s12,  997805, 20);
   3056         $s4 += self::mul($s12,  136657, 18);
   3057         $s5 -= self::mul($s12,  683901, 20);
   3058 
   3059         /** @var int $carry0 */
   3060         $carry0 = $s0 >> 21;
   3061         $s1 += $carry0;
   3062         $s0 -= $carry0 << 21;
   3063         /** @var int $carry1 */
   3064         $carry1 = $s1 >> 21;
   3065         $s2 += $carry1;
   3066         $s1 -= $carry1 << 21;
   3067         /** @var int $carry2 */
   3068         $carry2 = $s2 >> 21;
   3069         $s3 += $carry2;
   3070         $s2 -= $carry2 << 21;
   3071         /** @var int $carry3 */
   3072         $carry3 = $s3 >> 21;
   3073         $s4 += $carry3;
   3074         $s3 -= $carry3 << 21;
   3075         /** @var int $carry4 */
   3076         $carry4 = $s4 >> 21;
   3077         $s5 += $carry4;
   3078         $s4 -= $carry4 << 21;
   3079         /** @var int $carry5 */
   3080         $carry5 = $s5 >> 21;
   3081         $s6 += $carry5;
   3082         $s5 -= $carry5 << 21;
   3083         /** @var int $carry6 */
   3084         $carry6 = $s6 >> 21;
   3085         $s7 += $carry6;
   3086         $s6 -= $carry6 << 21;
   3087         /** @var int $carry7 */
   3088         $carry7 = $s7 >> 21;
   3089         $s8 += $carry7;
   3090         $s7 -= $carry7 << 21;
   3091         /** @var int $carry8 */
   3092         $carry8 = $s8 >> 21;
   3093         $s9 += $carry8;
   3094         $s8 -= $carry8 << 21;
   3095         /** @var int $carry9 */
   3096         $carry9 = $s9 >> 21;
   3097         $s10 += $carry9;
   3098         $s9 -= $carry9 << 21;
   3099         /** @var int $carry10 */
   3100         $carry10 = $s10 >> 21;
   3101         $s11 += $carry10;
   3102         $s10 -= $carry10 << 21;
   3103 
   3104         /**
   3105          * @var array<int, int>
   3106          */
   3107         $arr = array(
   3108             (int) ($s0 >> 0),
   3109             (int) ($s0 >> 8),
   3110             (int) (($s0 >> 16) | $s1 << 5),
   3111             (int) ($s1 >> 3),
   3112             (int) ($s1 >> 11),
   3113             (int) (($s1 >> 19) | $s2 << 2),
   3114             (int) ($s2 >> 6),
   3115             (int) (($s2 >> 14) | $s3 << 7),
   3116             (int) ($s3 >> 1),
   3117             (int) ($s3 >> 9),
   3118             (int) (($s3 >> 17) | $s4 << 4),
   3119             (int) ($s4 >> 4),
   3120             (int) ($s4 >> 12),
   3121             (int) (($s4 >> 20) | $s5 << 1),
   3122             (int) ($s5 >> 7),
   3123             (int) (($s5 >> 15) | $s6 << 6),
   3124             (int) ($s6 >> 2),
   3125             (int) ($s6 >> 10),
   3126             (int) (($s6 >> 18) | $s7 << 3),
   3127             (int) ($s7 >> 5),
   3128             (int) ($s7 >> 13),
   3129             (int) ($s8 >> 0),
   3130             (int) ($s8 >> 8),
   3131             (int) (($s8 >> 16) | $s9 << 5),
   3132             (int) ($s9 >> 3),
   3133             (int) ($s9 >> 11),
   3134             (int) (($s9 >> 19) | $s10 << 2),
   3135             (int) ($s10 >> 6),
   3136             (int) (($s10 >> 14) | $s11 << 7),
   3137             (int) ($s11 >> 1),
   3138             (int) ($s11 >> 9),
   3139             (int) $s11 >> 17
   3140         );
   3141         return self::intArrayToString($arr);
   3142     }
   3143 
   3144     /**
   3145      * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
   3146      *
   3147      * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
   3148      * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
   3149      */
   3150     public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A)
   3151     {
   3152         /** @var array<int, int> $aslide */
   3153         $aslide = array(
   3154             13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
   3155             0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
   3156             0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
   3157             0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
   3158             0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
   3159             0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
   3160             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3161             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3162             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3163             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3164             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   3165             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
   3166         );
   3167 
   3168         /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
   3169         $Ai = array();
   3170 
   3171         # ge_p3_to_cached(&Ai[0], A);
   3172         $Ai[0] = self::ge_p3_to_cached($A);
   3173         # ge_p3_dbl(&t, A);
   3174         $t = self::ge_p3_dbl($A);
   3175         # ge_p1p1_to_p3(&A2, &t);
   3176         $A2 = self::ge_p1p1_to_p3($t);
   3177 
   3178         for ($i = 1; $i < 8; ++$i) {
   3179             # ge_add(&t, &A2, &Ai[0]);
   3180             $t = self::ge_add($A2, $Ai[$i - 1]);
   3181             # ge_p1p1_to_p3(&u, &t);
   3182             $u = self::ge_p1p1_to_p3($t);
   3183             # ge_p3_to_cached(&Ai[i], &u);
   3184             $Ai[$i] = self::ge_p3_to_cached($u);
   3185         }
   3186 
   3187         $r = self::ge_p3_0();
   3188         for ($i = 252; $i >= 0; --$i) {
   3189             $t = self::ge_p3_dbl($r);
   3190             if ($aslide[$i] > 0) {
   3191                 # ge_p1p1_to_p3(&u, &t);
   3192                 $u = self::ge_p1p1_to_p3($t);
   3193                 # ge_add(&t, &u, &Ai[aslide[i] / 2]);
   3194                 $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
   3195             } elseif ($aslide[$i] < 0) {
   3196                 # ge_p1p1_to_p3(&u, &t);
   3197                 $u = self::ge_p1p1_to_p3($t);
   3198                 # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
   3199                 $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
   3200             }
   3201         }
   3202 
   3203         # ge_p1p1_to_p3(r, &t);
   3204         return self::ge_p1p1_to_p3($t);
   3205     }
   3206 
   3207     /**
   3208      * @param string $a
   3209      * @param string $b
   3210      * @return string
   3211      */
   3212     public static function sc25519_mul($a, $b)
   3213     {
   3214         //    int64_t a0  = 2097151 & load_3(a);
   3215         //    int64_t a1  = 2097151 & (load_4(a + 2) >> 5);
   3216         //    int64_t a2  = 2097151 & (load_3(a + 5) >> 2);
   3217         //    int64_t a3  = 2097151 & (load_4(a + 7) >> 7);
   3218         //    int64_t a4  = 2097151 & (load_4(a + 10) >> 4);
   3219         //    int64_t a5  = 2097151 & (load_3(a + 13) >> 1);
   3220         //    int64_t a6  = 2097151 & (load_4(a + 15) >> 6);
   3221         //    int64_t a7  = 2097151 & (load_3(a + 18) >> 3);
   3222         //    int64_t a8  = 2097151 & load_3(a + 21);
   3223         //    int64_t a9  = 2097151 & (load_4(a + 23) >> 5);
   3224         //    int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
   3225         //    int64_t a11 = (load_4(a + 28) >> 7);
   3226         $a0  = 2097151 &  self::load_3(self::substr($a, 0, 3));
   3227         $a1  = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
   3228         $a2  = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
   3229         $a3  = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
   3230         $a4  = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
   3231         $a5  = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
   3232         $a6  = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
   3233         $a7  = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
   3234         $a8  = 2097151 &  self::load_3(self::substr($a, 21, 3));
   3235         $a9  = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
   3236         $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
   3237         $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
   3238 
   3239         //    int64_t b0  = 2097151 & load_3(b);
   3240         //    int64_t b1  = 2097151 & (load_4(b + 2) >> 5);
   3241         //    int64_t b2  = 2097151 & (load_3(b + 5) >> 2);
   3242         //    int64_t b3  = 2097151 & (load_4(b + 7) >> 7);
   3243         //    int64_t b4  = 2097151 & (load_4(b + 10) >> 4);
   3244         //    int64_t b5  = 2097151 & (load_3(b + 13) >> 1);
   3245         //    int64_t b6  = 2097151 & (load_4(b + 15) >> 6);
   3246         //    int64_t b7  = 2097151 & (load_3(b + 18) >> 3);
   3247         //    int64_t b8  = 2097151 & load_3(b + 21);
   3248         //    int64_t b9  = 2097151 & (load_4(b + 23) >> 5);
   3249         //    int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
   3250         //    int64_t b11 = (load_4(b + 28) >> 7);
   3251         $b0  = 2097151 &  self::load_3(self::substr($b, 0, 3));
   3252         $b1  = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
   3253         $b2  = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
   3254         $b3  = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
   3255         $b4  = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
   3256         $b5  = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
   3257         $b6  = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
   3258         $b7  = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
   3259         $b8  = 2097151 &  self::load_3(self::substr($b, 21, 3));
   3260         $b9  = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
   3261         $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
   3262         $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
   3263 
   3264         //    s0 = a0 * b0;
   3265         //    s1 = a0 * b1 + a1 * b0;
   3266         //    s2 = a0 * b2 + a1 * b1 + a2 * b0;
   3267         //    s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
   3268         //    s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
   3269         //    s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
   3270         //    s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
   3271         //    s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
   3272         //        a6 * b1 + a7 * b0;
   3273         //    s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
   3274         //        a6 * b2 + a7 * b1 + a8 * b0;
   3275         //    s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
   3276         //        a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
   3277         //    s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
   3278         //        a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
   3279         //    s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
   3280         //        a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
   3281         //    s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 +
   3282         //        a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
   3283         //    s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 +
   3284         //        a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
   3285         //    s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 +
   3286         //        a9 * b5 + a10 * b4 + a11 * b3;
   3287         //    s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 +
   3288         //        a10 * b5 + a11 * b4;
   3289         //    s16 =
   3290         //        a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
   3291         //    s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
   3292         //    s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
   3293         //    s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
   3294         //    s20 = a9 * b11 + a10 * b10 + a11 * b9;
   3295         //    s21 = a10 * b11 + a11 * b10;
   3296         //    s22 = a11 * b11;
   3297         //    s23 = 0;
   3298         $s0 = self::mul($a0, $b0, 22);
   3299         $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22);
   3300         $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22);
   3301         $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22);
   3302         $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) +
   3303             self::mul($a4, $b0, 22);
   3304         $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) +
   3305             self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22);
   3306         $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) +
   3307             self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22);
   3308         $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) +
   3309             self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22);
   3310         $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) +
   3311             self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) +
   3312             self::mul($a8, $b0, 22);
   3313         $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) +
   3314             self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) +
   3315             self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22);
   3316         $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) +
   3317             self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) +
   3318             self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22);
   3319         $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) +
   3320             self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) +
   3321             self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22);
   3322         $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) +
   3323             self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) +
   3324             self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22);
   3325         $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) +
   3326             self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) +
   3327             self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22);
   3328         $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) +
   3329             self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) +
   3330             self::mul($a11, $b3, 22);
   3331         $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) +
   3332             self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22);
   3333         $s16 =
   3334             self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) +
   3335             self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22);
   3336         $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) +
   3337             self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22);
   3338         $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22)
   3339             + self::mul($a11, $b7, 22);
   3340         $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) +
   3341             self::mul($a11, $b8, 22);
   3342         $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22);
   3343         $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22);
   3344         $s22 = self::mul($a11, $b11, 22);
   3345         $s23 = 0;
   3346 
   3347         //    carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
   3348         //    s1 += carry0;
   3349         //    s0 -= carry0 * ((uint64_t) 1L << 21);
   3350         $carry0 = ($s0 + (1 << 20)) >> 21;
   3351         $s1 += $carry0;
   3352         $s0 -= $carry0 << 21;
   3353         //    carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
   3354         //    s3 += carry2;
   3355         //    s2 -= carry2 * ((uint64_t) 1L << 21);
   3356         $carry2 = ($s2 + (1 << 20)) >> 21;
   3357         $s3 += $carry2;
   3358         $s2 -= $carry2 << 21;
   3359         //    carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
   3360         //    s5 += carry4;
   3361         //    s4 -= carry4 * ((uint64_t) 1L << 21);
   3362         $carry4 = ($s4 + (1 << 20)) >> 21;
   3363         $s5 += $carry4;
   3364         $s4 -= $carry4 << 21;
   3365         //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
   3366         //    s7 += carry6;
   3367         //    s6 -= carry6 * ((uint64_t) 1L << 21);
   3368         $carry6 = ($s6 + (1 << 20)) >> 21;
   3369         $s7 += $carry6;
   3370         $s6 -= $carry6 << 21;
   3371         //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
   3372         //    s9 += carry8;
   3373         //    s8 -= carry8 * ((uint64_t) 1L << 21);
   3374         $carry8 = ($s8 + (1 << 20)) >> 21;
   3375         $s9 += $carry8;
   3376         $s8 -= $carry8 << 21;
   3377         //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
   3378         //    s11 += carry10;
   3379         //    s10 -= carry10 * ((uint64_t) 1L << 21);
   3380         $carry10 = ($s10 + (1 << 20)) >> 21;
   3381         $s11 += $carry10;
   3382         $s10 -= $carry10 << 21;
   3383         //    carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
   3384         //    s13 += carry12;
   3385         //    s12 -= carry12 * ((uint64_t) 1L << 21);
   3386         $carry12 = ($s12 + (1 << 20)) >> 21;
   3387         $s13 += $carry12;
   3388         $s12 -= $carry12 << 21;
   3389         //    carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
   3390         //    s15 += carry14;
   3391         //    s14 -= carry14 * ((uint64_t) 1L << 21);
   3392         $carry14 = ($s14 + (1 << 20)) >> 21;
   3393         $s15 += $carry14;
   3394         $s14 -= $carry14 << 21;
   3395         //    carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
   3396         //    s17 += carry16;
   3397         //    s16 -= carry16 * ((uint64_t) 1L << 21);
   3398         $carry16 = ($s16 + (1 << 20)) >> 21;
   3399         $s17 += $carry16;
   3400         $s16 -= $carry16 << 21;
   3401         //    carry18 = (s18 + (int64_t) (1L << 20)) >> 21;
   3402         //    s19 += carry18;
   3403         //    s18 -= carry18 * ((uint64_t) 1L << 21);
   3404         $carry18 = ($s18 + (1 << 20)) >> 21;
   3405         $s19 += $carry18;
   3406         $s18 -= $carry18 << 21;
   3407         //    carry20 = (s20 + (int64_t) (1L << 20)) >> 21;
   3408         //    s21 += carry20;
   3409         //    s20 -= carry20 * ((uint64_t) 1L << 21);
   3410         $carry20 = ($s20 + (1 << 20)) >> 21;
   3411         $s21 += $carry20;
   3412         $s20 -= $carry20 << 21;
   3413         //    carry22 = (s22 + (int64_t) (1L << 20)) >> 21;
   3414         //    s23 += carry22;
   3415         //    s22 -= carry22 * ((uint64_t) 1L << 21);
   3416         $carry22 = ($s22 + (1 << 20)) >> 21;
   3417         $s23 += $carry22;
   3418         $s22 -= $carry22 << 21;
   3419 
   3420         //    carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
   3421         //    s2 += carry1;
   3422         //    s1 -= carry1 * ((uint64_t) 1L << 21);
   3423         $carry1 = ($s1 + (1 << 20)) >> 21;
   3424         $s2 += $carry1;
   3425         $s1 -= $carry1 << 21;
   3426         //    carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
   3427         //    s4 += carry3;
   3428         //    s3 -= carry3 * ((uint64_t) 1L << 21);
   3429         $carry3 = ($s3 + (1 << 20)) >> 21;
   3430         $s4 += $carry3;
   3431         $s3 -= $carry3 << 21;
   3432         //    carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
   3433         //    s6 += carry5;
   3434         //    s5 -= carry5 * ((uint64_t) 1L << 21);
   3435         $carry5 = ($s5 + (1 << 20)) >> 21;
   3436         $s6 += $carry5;
   3437         $s5 -= $carry5 << 21;
   3438         //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
   3439         //    s8 += carry7;
   3440         //    s7 -= carry7 * ((uint64_t) 1L << 21);
   3441         $carry7 = ($s7 + (1 << 20)) >> 21;
   3442         $s8 += $carry7;
   3443         $s7 -= $carry7 << 21;
   3444         //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
   3445         //    s10 += carry9;
   3446         //    s9 -= carry9 * ((uint64_t) 1L << 21);
   3447         $carry9 = ($s9 + (1 << 20)) >> 21;
   3448         $s10 += $carry9;
   3449         $s9 -= $carry9 << 21;
   3450         //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
   3451         //    s12 += carry11;
   3452         //    s11 -= carry11 * ((uint64_t) 1L << 21);
   3453         $carry11 = ($s11 + (1 << 20)) >> 21;
   3454         $s12 += $carry11;
   3455         $s11 -= $carry11 << 21;
   3456         //    carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
   3457         //    s14 += carry13;
   3458         //    s13 -= carry13 * ((uint64_t) 1L << 21);
   3459         $carry13 = ($s13 + (1 << 20)) >> 21;
   3460         $s14 += $carry13;
   3461         $s13 -= $carry13 << 21;
   3462         //    carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
   3463         //    s16 += carry15;
   3464         //    s15 -= carry15 * ((uint64_t) 1L << 21);
   3465         $carry15 = ($s15 + (1 << 20)) >> 21;
   3466         $s16 += $carry15;
   3467         $s15 -= $carry15 << 21;
   3468         //    carry17 = (s17 + (int64_t) (1L << 20)) >> 21;
   3469         //    s18 += carry17;
   3470         //    s17 -= carry17 * ((uint64_t) 1L << 21);
   3471         $carry17 = ($s17 + (1 << 20)) >> 21;
   3472         $s18 += $carry17;
   3473         $s17 -= $carry17 << 21;
   3474         //    carry19 = (s19 + (int64_t) (1L << 20)) >> 21;
   3475         //    s20 += carry19;
   3476         //    s19 -= carry19 * ((uint64_t) 1L << 21);
   3477         $carry19 = ($s19 + (1 << 20)) >> 21;
   3478         $s20 += $carry19;
   3479         $s19 -= $carry19 << 21;
   3480         //    carry21 = (s21 + (int64_t) (1L << 20)) >> 21;
   3481         //    s22 += carry21;
   3482         //    s21 -= carry21 * ((uint64_t) 1L << 21);
   3483         $carry21 = ($s21 + (1 << 20)) >> 21;
   3484         $s22 += $carry21;
   3485         $s21 -= $carry21 << 21;
   3486 
   3487         //    s11 += s23 * 666643;
   3488         //    s12 += s23 * 470296;
   3489         //    s13 += s23 * 654183;
   3490         //    s14 -= s23 * 997805;
   3491         //    s15 += s23 * 136657;
   3492         //    s16 -= s23 * 683901;
   3493         $s11 += self::mul($s23, 666643, 20);
   3494         $s12 += self::mul($s23, 470296, 19);
   3495         $s13 += self::mul($s23, 654183, 20);
   3496         $s14 -= self::mul($s23, 997805, 20);
   3497         $s15 += self::mul($s23, 136657, 18);
   3498         $s16 -= self::mul($s23, 683901, 20);
   3499 
   3500         //    s10 += s22 * 666643;
   3501         //    s11 += s22 * 470296;
   3502         //    s12 += s22 * 654183;
   3503         //    s13 -= s22 * 997805;
   3504         //    s14 += s22 * 136657;
   3505         //    s15 -= s22 * 683901;
   3506         $s10 += self::mul($s22, 666643, 20);
   3507         $s11 += self::mul($s22, 470296, 19);
   3508         $s12 += self::mul($s22, 654183, 20);
   3509         $s13 -= self::mul($s22, 997805, 20);
   3510         $s14 += self::mul($s22, 136657, 18);
   3511         $s15 -= self::mul($s22, 683901, 20);
   3512 
   3513         //    s9 += s21 * 666643;
   3514         //    s10 += s21 * 470296;
   3515         //    s11 += s21 * 654183;
   3516         //    s12 -= s21 * 997805;
   3517         //    s13 += s21 * 136657;
   3518         //    s14 -= s21 * 683901;
   3519         $s9 += self::mul($s21, 666643, 20);
   3520         $s10 += self::mul($s21, 470296, 19);
   3521         $s11 += self::mul($s21, 654183, 20);
   3522         $s12 -= self::mul($s21, 997805, 20);
   3523         $s13 += self::mul($s21, 136657, 18);
   3524         $s14 -= self::mul($s21, 683901, 20);
   3525 
   3526         //    s8 += s20 * 666643;
   3527         //    s9 += s20 * 470296;
   3528         //    s10 += s20 * 654183;
   3529         //    s11 -= s20 * 997805;
   3530         //    s12 += s20 * 136657;
   3531         //    s13 -= s20 * 683901;
   3532         $s8 += self::mul($s20, 666643, 20);
   3533         $s9 += self::mul($s20, 470296, 19);
   3534         $s10 += self::mul($s20, 654183, 20);
   3535         $s11 -= self::mul($s20, 997805, 20);
   3536         $s12 += self::mul($s20, 136657, 18);
   3537         $s13 -= self::mul($s20, 683901, 20);
   3538 
   3539         //    s7 += s19 * 666643;
   3540         //    s8 += s19 * 470296;
   3541         //    s9 += s19 * 654183;
   3542         //    s10 -= s19 * 997805;
   3543         //    s11 += s19 * 136657;
   3544         //    s12 -= s19 * 683901;
   3545         $s7 += self::mul($s19, 666643, 20);
   3546         $s8 += self::mul($s19, 470296, 19);
   3547         $s9 += self::mul($s19, 654183, 20);
   3548         $s10 -= self::mul($s19, 997805, 20);
   3549         $s11 += self::mul($s19, 136657, 18);
   3550         $s12 -= self::mul($s19, 683901, 20);
   3551 
   3552         //    s6 += s18 * 666643;
   3553         //    s7 += s18 * 470296;
   3554         //    s8 += s18 * 654183;
   3555         //    s9 -= s18 * 997805;
   3556         //    s10 += s18 * 136657;
   3557         //    s11 -= s18 * 683901;
   3558         $s6 += self::mul($s18, 666643, 20);
   3559         $s7 += self::mul($s18, 470296, 19);
   3560         $s8 += self::mul($s18, 654183, 20);
   3561         $s9 -= self::mul($s18, 997805, 20);
   3562         $s10 += self::mul($s18, 136657, 18);
   3563         $s11 -= self::mul($s18, 683901, 20);
   3564 
   3565         //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
   3566         //    s7 += carry6;
   3567         //    s6 -= carry6 * ((uint64_t) 1L << 21);
   3568         $carry6 = ($s6 + (1 << 20)) >> 21;
   3569         $s7 += $carry6;
   3570         $s6 -= $carry6 << 21;
   3571         //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
   3572         //    s9 += carry8;
   3573         //    s8 -= carry8 * ((uint64_t) 1L << 21);
   3574         $carry8 = ($s8 + (1 << 20)) >> 21;
   3575         $s9 += $carry8;
   3576         $s8 -= $carry8 << 21;
   3577         //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
   3578         //    s11 += carry10;
   3579         //    s10 -= carry10 * ((uint64_t) 1L << 21);
   3580         $carry10 = ($s10 + (1 << 20)) >> 21;
   3581         $s11 += $carry10;
   3582         $s10 -= $carry10 << 21;
   3583         //    carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
   3584         //    s13 += carry12;
   3585         //    s12 -= carry12 * ((uint64_t) 1L << 21);
   3586         $carry12 = ($s12 + (1 << 20)) >> 21;
   3587         $s13 += $carry12;
   3588         $s12 -= $carry12 << 21;
   3589         //    carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
   3590         //    s15 += carry14;
   3591         //    s14 -= carry14 * ((uint64_t) 1L << 21);
   3592         $carry14 = ($s14 + (1 << 20)) >> 21;
   3593         $s15 += $carry14;
   3594         $s14 -= $carry14 << 21;
   3595         //    carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
   3596         //    s17 += carry16;
   3597         //    s16 -= carry16 * ((uint64_t) 1L << 21);
   3598         $carry16 = ($s16 + (1 << 20)) >> 21;
   3599         $s17 += $carry16;
   3600         $s16 -= $carry16 << 21;
   3601 
   3602         //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
   3603         //    s8 += carry7;
   3604         //    s7 -= carry7 * ((uint64_t) 1L << 21);
   3605         $carry7 = ($s7 + (1 << 20)) >> 21;
   3606         $s8 += $carry7;
   3607         $s7 -= $carry7 << 21;
   3608         //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
   3609         //    s10 += carry9;
   3610         //    s9 -= carry9 * ((uint64_t) 1L << 21);
   3611         $carry9 = ($s9 + (1 << 20)) >> 21;
   3612         $s10 += $carry9;
   3613         $s9 -= $carry9 << 21;
   3614         //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
   3615         //    s12 += carry11;
   3616         //    s11 -= carry11 * ((uint64_t) 1L << 21);
   3617         $carry11 = ($s11 + (1 << 20)) >> 21;
   3618         $s12 += $carry11;
   3619         $s11 -= $carry11 << 21;
   3620         //    carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
   3621         //    s14 += carry13;
   3622         //    s13 -= carry13 * ((uint64_t) 1L << 21);
   3623         $carry13 = ($s13 + (1 << 20)) >> 21;
   3624         $s14 += $carry13;
   3625         $s13 -= $carry13 << 21;
   3626         //    carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
   3627         //    s16 += carry15;
   3628         //    s15 -= carry15 * ((uint64_t) 1L << 21);
   3629         $carry15 = ($s15 + (1 << 20)) >> 21;
   3630         $s16 += $carry15;
   3631         $s15 -= $carry15 << 21;
   3632 
   3633         //    s5 += s17 * 666643;
   3634         //    s6 += s17 * 470296;
   3635         //    s7 += s17 * 654183;
   3636         //    s8 -= s17 * 997805;
   3637         //    s9 += s17 * 136657;
   3638         //    s10 -= s17 * 683901;
   3639         $s5 += self::mul($s17, 666643, 20);
   3640         $s6 += self::mul($s17, 470296, 19);
   3641         $s7 += self::mul($s17, 654183, 20);
   3642         $s8 -= self::mul($s17, 997805, 20);
   3643         $s9 += self::mul($s17, 136657, 18);
   3644         $s10 -= self::mul($s17, 683901, 20);
   3645 
   3646         //    s4 += s16 * 666643;
   3647         //    s5 += s16 * 470296;
   3648         //    s6 += s16 * 654183;
   3649         //    s7 -= s16 * 997805;
   3650         //    s8 += s16 * 136657;
   3651         //    s9 -= s16 * 683901;
   3652         $s4 += self::mul($s16, 666643, 20);
   3653         $s5 += self::mul($s16, 470296, 19);
   3654         $s6 += self::mul($s16, 654183, 20);
   3655         $s7 -= self::mul($s16, 997805, 20);
   3656         $s8 += self::mul($s16, 136657, 18);
   3657         $s9 -= self::mul($s16, 683901, 20);
   3658 
   3659         //    s3 += s15 * 666643;
   3660         //    s4 += s15 * 470296;
   3661         //    s5 += s15 * 654183;
   3662         //    s6 -= s15 * 997805;
   3663         //    s7 += s15 * 136657;
   3664         //    s8 -= s15 * 683901;
   3665         $s3 += self::mul($s15, 666643, 20);
   3666         $s4 += self::mul($s15, 470296, 19);
   3667         $s5 += self::mul($s15, 654183, 20);
   3668         $s6 -= self::mul($s15, 997805, 20);
   3669         $s7 += self::mul($s15, 136657, 18);
   3670         $s8 -= self::mul($s15, 683901, 20);
   3671 
   3672         //    s2 += s14 * 666643;
   3673         //    s3 += s14 * 470296;
   3674         //    s4 += s14 * 654183;
   3675         //    s5 -= s14 * 997805;
   3676         //    s6 += s14 * 136657;
   3677         //    s7 -= s14 * 683901;
   3678         $s2 += self::mul($s14, 666643, 20);
   3679         $s3 += self::mul($s14, 470296, 19);
   3680         $s4 += self::mul($s14, 654183, 20);
   3681         $s5 -= self::mul($s14, 997805, 20);
   3682         $s6 += self::mul($s14, 136657, 18);
   3683         $s7 -= self::mul($s14, 683901, 20);
   3684 
   3685         //    s1 += s13 * 666643;
   3686         //    s2 += s13 * 470296;
   3687         //    s3 += s13 * 654183;
   3688         //    s4 -= s13 * 997805;
   3689         //    s5 += s13 * 136657;
   3690         //    s6 -= s13 * 683901;
   3691         $s1 += self::mul($s13, 666643, 20);
   3692         $s2 += self::mul($s13, 470296, 19);
   3693         $s3 += self::mul($s13, 654183, 20);
   3694         $s4 -= self::mul($s13, 997805, 20);
   3695         $s5 += self::mul($s13, 136657, 18);
   3696         $s6 -= self::mul($s13, 683901, 20);
   3697 
   3698         //    s0 += s12 * 666643;
   3699         //    s1 += s12 * 470296;
   3700         //    s2 += s12 * 654183;
   3701         //    s3 -= s12 * 997805;
   3702         //    s4 += s12 * 136657;
   3703         //    s5 -= s12 * 683901;
   3704         //    s12 = 0;
   3705         $s0 += self::mul($s12, 666643, 20);
   3706         $s1 += self::mul($s12, 470296, 19);
   3707         $s2 += self::mul($s12, 654183, 20);
   3708         $s3 -= self::mul($s12, 997805, 20);
   3709         $s4 += self::mul($s12, 136657, 18);
   3710         $s5 -= self::mul($s12, 683901, 20);
   3711         $s12 = 0;
   3712 
   3713         //    carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
   3714         //    s1 += carry0;
   3715         //    s0 -= carry0 * ((uint64_t) 1L << 21);
   3716         $carry0 = ($s0 + (1 << 20)) >> 21;
   3717         $s1 += $carry0;
   3718         $s0 -= $carry0 << 21;
   3719         //    carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
   3720         //    s3 += carry2;
   3721         //    s2 -= carry2 * ((uint64_t) 1L << 21);
   3722         $carry2 = ($s2 + (1 << 20)) >> 21;
   3723         $s3 += $carry2;
   3724         $s2 -= $carry2 << 21;
   3725         //    carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
   3726         //    s5 += carry4;
   3727         //    s4 -= carry4 * ((uint64_t) 1L << 21);
   3728         $carry4 = ($s4 + (1 << 20)) >> 21;
   3729         $s5 += $carry4;
   3730         $s4 -= $carry4 << 21;
   3731         //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
   3732         //    s7 += carry6;
   3733         //    s6 -= carry6 * ((uint64_t) 1L << 21);
   3734         $carry6 = ($s6 + (1 << 20)) >> 21;
   3735         $s7 += $carry6;
   3736         $s6 -= $carry6 << 21;
   3737         //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
   3738         //    s9 += carry8;
   3739         //    s8 -= carry8 * ((uint64_t) 1L << 21);
   3740         $carry8 = ($s8 + (1 << 20)) >> 21;
   3741         $s9 += $carry8;
   3742         $s8 -= $carry8 << 21;
   3743         //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
   3744         //    s11 += carry10;
   3745         //    s10 -= carry10 * ((uint64_t) 1L << 21);
   3746         $carry10 = ($s10 + (1 << 20)) >> 21;
   3747         $s11 += $carry10;
   3748         $s10 -= $carry10 << 21;
   3749 
   3750         //    carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
   3751         //    s2 += carry1;
   3752         //    s1 -= carry1 * ((uint64_t) 1L << 21);
   3753         $carry1 = ($s1 + (1 << 20)) >> 21;
   3754         $s2 += $carry1;
   3755         $s1 -= $carry1 << 21;
   3756         //    carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
   3757         //    s4 += carry3;
   3758         //    s3 -= carry3 * ((uint64_t) 1L << 21);
   3759         $carry3 = ($s3 + (1 << 20)) >> 21;
   3760         $s4 += $carry3;
   3761         $s3 -= $carry3 << 21;
   3762         //    carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
   3763         //    s6 += carry5;
   3764         //    s5 -= carry5 * ((uint64_t) 1L << 21);
   3765         $carry5 = ($s5 + (1 << 20)) >> 21;
   3766         $s6 += $carry5;
   3767         $s5 -= $carry5 << 21;
   3768         //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
   3769         //    s8 += carry7;
   3770         //    s7 -= carry7 * ((uint64_t) 1L << 21);
   3771         $carry7 = ($s7 + (1 << 20)) >> 21;
   3772         $s8 += $carry7;
   3773         $s7 -= $carry7 << 21;
   3774         //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
   3775         //    s10 += carry9;
   3776         //    s9 -= carry9 * ((uint64_t) 1L << 21);
   3777         $carry9 = ($s9 + (1 << 20)) >> 21;
   3778         $s10 += $carry9;
   3779         $s9 -= $carry9 << 21;
   3780         //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
   3781         //    s12 += carry11;
   3782         //    s11 -= carry11 * ((uint64_t) 1L << 21);
   3783         $carry11 = ($s11 + (1 << 20)) >> 21;
   3784         $s12 += $carry11;
   3785         $s11 -= $carry11 << 21;
   3786 
   3787         //    s0 += s12 * 666643;
   3788         //    s1 += s12 * 470296;
   3789         //    s2 += s12 * 654183;
   3790         //    s3 -= s12 * 997805;
   3791         //    s4 += s12 * 136657;
   3792         //    s5 -= s12 * 683901;
   3793         //    s12 = 0;
   3794         $s0 += self::mul($s12, 666643, 20);
   3795         $s1 += self::mul($s12, 470296, 19);
   3796         $s2 += self::mul($s12, 654183, 20);
   3797         $s3 -= self::mul($s12, 997805, 20);
   3798         $s4 += self::mul($s12, 136657, 18);
   3799         $s5 -= self::mul($s12, 683901, 20);
   3800         $s12 = 0;
   3801 
   3802         //    carry0 = s0 >> 21;
   3803         //    s1 += carry0;
   3804         //    s0 -= carry0 * ((uint64_t) 1L << 21);
   3805         $carry0 = $s0 >> 21;
   3806         $s1 += $carry0;
   3807         $s0 -= $carry0 << 21;
   3808         //    carry1 = s1 >> 21;
   3809         //    s2 += carry1;
   3810         //    s1 -= carry1 * ((uint64_t) 1L << 21);
   3811         $carry1 = $s1 >> 21;
   3812         $s2 += $carry1;
   3813         $s1 -= $carry1 << 21;
   3814         //    carry2 = s2 >> 21;
   3815         //    s3 += carry2;
   3816         //    s2 -= carry2 * ((uint64_t) 1L << 21);
   3817         $carry2 = $s2 >> 21;
   3818         $s3 += $carry2;
   3819         $s2 -= $carry2 << 21;
   3820         //    carry3 = s3 >> 21;
   3821         //    s4 += carry3;
   3822         //    s3 -= carry3 * ((uint64_t) 1L << 21);
   3823         $carry3 = $s3 >> 21;
   3824         $s4 += $carry3;
   3825         $s3 -= $carry3 << 21;
   3826         //    carry4 = s4 >> 21;
   3827         //    s5 += carry4;
   3828         //    s4 -= carry4 * ((uint64_t) 1L << 21);
   3829         $carry4 = $s4 >> 21;
   3830         $s5 += $carry4;
   3831         $s4 -= $carry4 << 21;
   3832         //    carry5 = s5 >> 21;
   3833         //    s6 += carry5;
   3834         //    s5 -= carry5 * ((uint64_t) 1L << 21);
   3835         $carry5 = $s5 >> 21;
   3836         $s6 += $carry5;
   3837         $s5 -= $carry5 << 21;
   3838         //    carry6 = s6 >> 21;
   3839         //    s7 += carry6;
   3840         //    s6 -= carry6 * ((uint64_t) 1L << 21);
   3841         $carry6 = $s6 >> 21;
   3842         $s7 += $carry6;
   3843         $s6 -= $carry6 << 21;
   3844         //    carry7 = s7 >> 21;
   3845         //    s8 += carry7;
   3846         //    s7 -= carry7 * ((uint64_t) 1L << 21);
   3847         $carry7 = $s7 >> 21;
   3848         $s8 += $carry7;
   3849         $s7 -= $carry7 << 21;
   3850         //    carry8 = s8 >> 21;
   3851         //    s9 += carry8;
   3852         //    s8 -= carry8 * ((uint64_t) 1L << 21);
   3853         $carry8 = $s8 >> 21;
   3854         $s9 += $carry8;
   3855         $s8 -= $carry8 << 21;
   3856         //    carry9 = s9 >> 21;
   3857         //    s10 += carry9;
   3858         //    s9 -= carry9 * ((uint64_t) 1L << 21);
   3859         $carry9 = $s9 >> 21;
   3860         $s10 += $carry9;
   3861         $s9 -= $carry9 << 21;
   3862         //    carry10 = s10 >> 21;
   3863         //    s11 += carry10;
   3864         //    s10 -= carry10 * ((uint64_t) 1L << 21);
   3865         $carry10 = $s10 >> 21;
   3866         $s11 += $carry10;
   3867         $s10 -= $carry10 << 21;
   3868         //    carry11 = s11 >> 21;
   3869         //    s12 += carry11;
   3870         //    s11 -= carry11 * ((uint64_t) 1L << 21);
   3871         $carry11 = $s11 >> 21;
   3872         $s12 += $carry11;
   3873         $s11 -= $carry11 << 21;
   3874 
   3875         //    s0 += s12 * 666643;
   3876         //    s1 += s12 * 470296;
   3877         //    s2 += s12 * 654183;
   3878         //    s3 -= s12 * 997805;
   3879         //    s4 += s12 * 136657;
   3880         //    s5 -= s12 * 683901;
   3881         $s0 += self::mul($s12, 666643, 20);
   3882         $s1 += self::mul($s12, 470296, 19);
   3883         $s2 += self::mul($s12, 654183, 20);
   3884         $s3 -= self::mul($s12, 997805, 20);
   3885         $s4 += self::mul($s12, 136657, 18);
   3886         $s5 -= self::mul($s12, 683901, 20);
   3887 
   3888         //    carry0 = s0 >> 21;
   3889         //    s1 += carry0;
   3890         //    s0 -= carry0 * ((uint64_t) 1L << 21);
   3891         $carry0 = $s0 >> 21;
   3892         $s1 += $carry0;
   3893         $s0 -= $carry0 << 21;
   3894         //    carry1 = s1 >> 21;
   3895         //    s2 += carry1;
   3896         //    s1 -= carry1 * ((uint64_t) 1L << 21);
   3897         $carry1 = $s1 >> 21;
   3898         $s2 += $carry1;
   3899         $s1 -= $carry1 << 21;
   3900         //    carry2 = s2 >> 21;
   3901         //    s3 += carry2;
   3902         //    s2 -= carry2 * ((uint64_t) 1L << 21);
   3903         $carry2 = $s2 >> 21;
   3904         $s3 += $carry2;
   3905         $s2 -= $carry2 << 21;
   3906         //    carry3 = s3 >> 21;
   3907         //    s4 += carry3;
   3908         //    s3 -= carry3 * ((uint64_t) 1L << 21);
   3909         $carry3 = $s3 >> 21;
   3910         $s4 += $carry3;
   3911         $s3 -= $carry3 << 21;
   3912         //    carry4 = s4 >> 21;
   3913         //    s5 += carry4;
   3914         //    s4 -= carry4 * ((uint64_t) 1L << 21);
   3915         $carry4 = $s4 >> 21;
   3916         $s5 += $carry4;
   3917         $s4 -= $carry4 << 21;
   3918         //    carry5 = s5 >> 21;
   3919         //    s6 += carry5;
   3920         //    s5 -= carry5 * ((uint64_t) 1L << 21);
   3921         $carry5 = $s5 >> 21;
   3922         $s6 += $carry5;
   3923         $s5 -= $carry5 << 21;
   3924         //    carry6 = s6 >> 21;
   3925         //    s7 += carry6;
   3926         //    s6 -= carry6 * ((uint64_t) 1L << 21);
   3927         $carry6 = $s6 >> 21;
   3928         $s7 += $carry6;
   3929         $s6 -= $carry6 << 21;
   3930         //    carry7 = s7 >> 21;
   3931         //    s8 += carry7;
   3932         //    s7 -= carry7 * ((uint64_t) 1L << 21);
   3933         $carry7 = $s7 >> 21;
   3934         $s8 += $carry7;
   3935         $s7 -= $carry7 << 21;
   3936         //    carry8 = s8 >> 21;
   3937         //    s9 += carry8;
   3938         //    s8 -= carry8 * ((uint64_t) 1L << 21);
   3939         $carry8 = $s8 >> 21;
   3940         $s9 += $carry8;
   3941         $s8 -= $carry8 << 21;
   3942         //    carry9 = s9 >> 21;
   3943         //    s10 += carry9;
   3944         //    s9 -= carry9 * ((uint64_t) 1L << 21);
   3945         $carry9 = $s9 >> 21;
   3946         $s10 += $carry9;
   3947         $s9 -= $carry9 << 21;
   3948         //    carry10 = s10 >> 21;
   3949         //    s11 += carry10;
   3950         //    s10 -= carry10 * ((uint64_t) 1L << 21);
   3951         $carry10 = $s10 >> 21;
   3952         $s11 += $carry10;
   3953         $s10 -= $carry10 << 21;
   3954 
   3955         $s = array_fill(0, 32, 0);
   3956         // s[0]  = s0 >> 0;
   3957         $s[0]  = $s0 >> 0;
   3958         // s[1]  = s0 >> 8;
   3959         $s[1]  = $s0 >> 8;
   3960         // s[2]  = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5));
   3961         $s[2]  = ($s0 >> 16) | ($s1 << 5);
   3962         // s[3]  = s1 >> 3;
   3963         $s[3]  = $s1 >> 3;
   3964         // s[4]  = s1 >> 11;
   3965         $s[4]  = $s1 >> 11;
   3966         // s[5]  = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2));
   3967         $s[5]  = ($s1 >> 19) | ($s2 << 2);
   3968         // s[6]  = s2 >> 6;
   3969         $s[6]  = $s2 >> 6;
   3970         // s[7]  = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7));
   3971         $s[7]  = ($s2 >> 14) | ($s3 << 7);
   3972         // s[8]  = s3 >> 1;
   3973         $s[8]  = $s3 >> 1;
   3974         // s[9]  = s3 >> 9;
   3975         $s[9]  = $s3 >> 9;
   3976         // s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4));
   3977         $s[10] = ($s3 >> 17) | ($s4 << 4);
   3978         // s[11] = s4 >> 4;
   3979         $s[11] = $s4 >> 4;
   3980         // s[12] = s4 >> 12;
   3981         $s[12] = $s4 >> 12;
   3982         // s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1));
   3983         $s[13] = ($s4 >> 20) | ($s5 << 1);
   3984         // s[14] = s5 >> 7;
   3985         $s[14] = $s5 >> 7;
   3986         // s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6));
   3987         $s[15] = ($s5 >> 15) | ($s6 << 6);
   3988         // s[16] = s6 >> 2;
   3989         $s[16] = $s6 >> 2;
   3990         // s[17] = s6 >> 10;
   3991         $s[17] = $s6 >> 10;
   3992         // s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3));
   3993         $s[18] = ($s6 >> 18) | ($s7 << 3);
   3994         // s[19] = s7 >> 5;
   3995         $s[19] = $s7 >> 5;
   3996         // s[20] = s7 >> 13;
   3997         $s[20] = $s7 >> 13;
   3998         // s[21] = s8 >> 0;
   3999         $s[21] = $s8 >> 0;
   4000         // s[22] = s8 >> 8;
   4001         $s[22] = $s8 >> 8;
   4002         // s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5));
   4003         $s[23] = ($s8 >> 16) | ($s9 << 5);
   4004         // s[24] = s9 >> 3;
   4005         $s[24] = $s9 >> 3;
   4006         // s[25] = s9 >> 11;
   4007         $s[25] = $s9 >> 11;
   4008         // s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2));
   4009         $s[26] = ($s9 >> 19) | ($s10 << 2);
   4010         // s[27] = s10 >> 6;
   4011         $s[27] = $s10 >> 6;
   4012         // s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7));
   4013         $s[28] = ($s10 >> 14) | ($s11 << 7);
   4014         // s[29] = s11 >> 1;
   4015         $s[29] = $s11 >> 1;
   4016         // s[30] = s11 >> 9;
   4017         $s[30] = $s11 >> 9;
   4018         // s[31] = s11 >> 17;
   4019         $s[31] = $s11 >> 17;
   4020         return self::intArrayToString($s);
   4021     }
   4022 
   4023     /**
   4024      * @param string $s
   4025      * @return string
   4026      */
   4027     public static function sc25519_sq($s)
   4028     {
   4029         return self::sc25519_mul($s, $s);
   4030     }
   4031 
   4032     /**
   4033      * @param string $s
   4034      * @param int $n
   4035      * @param string $a
   4036      * @return string
   4037      */
   4038     public static function sc25519_sqmul($s, $n, $a)
   4039     {
   4040         for ($i = 0; $i < $n; ++$i) {
   4041             $s = self::sc25519_sq($s);
   4042         }
   4043         return self::sc25519_mul($s, $a);
   4044     }
   4045 
   4046     /**
   4047      * @param string $s
   4048      * @return string
   4049      */
   4050     public static function sc25519_invert($s)
   4051     {
   4052         $_10 = self::sc25519_sq($s);
   4053         $_11 = self::sc25519_mul($s, $_10);
   4054         $_100 = self::sc25519_mul($s, $_11);
   4055         $_1000 = self::sc25519_sq($_100);
   4056         $_1010 = self::sc25519_mul($_10, $_1000);
   4057         $_1011 = self::sc25519_mul($s, $_1010);
   4058         $_10000 = self::sc25519_sq($_1000);
   4059         $_10110 = self::sc25519_sq($_1011);
   4060         $_100000 = self::sc25519_mul($_1010, $_10110);
   4061         $_100110 = self::sc25519_mul($_10000, $_10110);
   4062         $_1000000 = self::sc25519_sq($_100000);
   4063         $_1010000 = self::sc25519_mul($_10000, $_1000000);
   4064         $_1010011 = self::sc25519_mul($_11, $_1010000);
   4065         $_1100011 = self::sc25519_mul($_10000, $_1010011);
   4066         $_1100111 = self::sc25519_mul($_100, $_1100011);
   4067         $_1101011 = self::sc25519_mul($_100, $_1100111);
   4068         $_10010011 = self::sc25519_mul($_1000000, $_1010011);
   4069         $_10010111 = self::sc25519_mul($_100, $_10010011);
   4070         $_10111101 = self::sc25519_mul($_100110, $_10010111);
   4071         $_11010011 = self::sc25519_mul($_10110, $_10111101);
   4072         $_11100111 = self::sc25519_mul($_1010000, $_10010111);
   4073         $_11101011 = self::sc25519_mul($_100, $_11100111);
   4074         $_11110101 = self::sc25519_mul($_1010, $_11101011);
   4075 
   4076         $recip = self::sc25519_mul($_1011, $_11110101);
   4077         $recip = self::sc25519_sqmul($recip, 126, $_1010011);
   4078         $recip = self::sc25519_sqmul($recip, 9, $_10);
   4079         $recip = self::sc25519_mul($recip, $_11110101);
   4080         $recip = self::sc25519_sqmul($recip, 7, $_1100111);
   4081         $recip = self::sc25519_sqmul($recip, 9, $_11110101);
   4082         $recip = self::sc25519_sqmul($recip, 11, $_10111101);
   4083         $recip = self::sc25519_sqmul($recip, 8, $_11100111);
   4084         $recip = self::sc25519_sqmul($recip, 9, $_1101011);
   4085         $recip = self::sc25519_sqmul($recip, 6, $_1011);
   4086         $recip = self::sc25519_sqmul($recip, 14, $_10010011);
   4087         $recip = self::sc25519_sqmul($recip, 10, $_1100011);
   4088         $recip = self::sc25519_sqmul($recip, 9, $_10010111);
   4089         $recip = self::sc25519_sqmul($recip, 10, $_11110101);
   4090         $recip = self::sc25519_sqmul($recip, 8, $_11010011);
   4091         return self::sc25519_sqmul($recip, 8, $_11101011);
   4092     }
   4093 
   4094     /**
   4095      * @param string $s
   4096      * @return string
   4097      */
   4098     public static function clamp($s)
   4099     {
   4100         $s_ = self::stringToIntArray($s);
   4101         $s_[0] &= 248;
   4102         $s_[31] |= 64;
   4103         $s_[31] &= 128;
   4104         return self::intArrayToString($s_);
   4105     }
   4106 }