[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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