[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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