[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/sodium_compat/src/Core/ -> Curve25519.php (source)

   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