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