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