[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

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 new ParagonIE_Sodium_Core_Curve25519_Fe();
  28      }
  29  
  30      /**
  31       * Get a field element of size 10 with a value of 1
  32       *
  33       * @internal You should not use this directly from another application
  34       *
  35       * @return ParagonIE_Sodium_Core_Curve25519_Fe
  36       */
  37      public static function fe_1()
  38      {
  39          $fe = new ParagonIE_Sodium_Core_Curve25519_Fe();
  40          $fe->e0 = 1;
  41          return $fe;
  42      }
  43  
  44      /**
  45       * Add two field elements.
  46       *
  47       * @internal You should not use this directly from another application
  48       *
  49       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
  50       * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
  51       * @return ParagonIE_Sodium_Core_Curve25519_Fe
  52       * @psalm-suppress MixedAssignment
  53       * @psalm-suppress MixedOperand
  54       */
  55      public static function fe_add(
  56          ParagonIE_Sodium_Core_Curve25519_Fe $f,
  57          ParagonIE_Sodium_Core_Curve25519_Fe $g
  58      ) {
  59          return new ParagonIE_Sodium_Core_Curve25519_Fe(
  60              (int)($f->e0 + $g->e0),
  61              (int)($f->e1 + $g->e1),
  62              (int)($f->e2 + $g->e2),
  63              (int)($f->e3 + $g->e3),
  64              (int)($f->e4 + $g->e4),
  65              (int)($f->e5 + $g->e5),
  66              (int)($f->e6 + $g->e6),
  67              (int)($f->e7 + $g->e7),
  68              (int)($f->e8 + $g->e8),
  69              (int)($f->e9 + $g->e9)
  70          );
  71      }
  72  
  73      /**
  74       * Constant-time conditional move.
  75       *
  76       * @internal You should not use this directly from another application
  77       *
  78       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
  79       * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
  80       * @param int $b
  81       * @return ParagonIE_Sodium_Core_Curve25519_Fe
  82       * @psalm-suppress MixedAssignment
  83       */
  84      public static function fe_cmov(
  85          ParagonIE_Sodium_Core_Curve25519_Fe $f,
  86          ParagonIE_Sodium_Core_Curve25519_Fe $g,
  87          $b = 0
  88      ) {
  89          $h = new ParagonIE_Sodium_Core_Curve25519_Fe();
  90          $b *= -1;
  91          $x = (($f->e0 ^ $g->e0) & $b); $h->e0 = $f->e0 ^ $x;
  92          $x = (($f->e1 ^ $g->e1) & $b); $h->e1 = $f->e1 ^ $x;
  93          $x = (($f->e2 ^ $g->e2) & $b); $h->e2 = $f->e2 ^ $x;
  94          $x = (($f->e3 ^ $g->e3) & $b); $h->e3 = $f->e3 ^ $x;
  95          $x = (($f->e4 ^ $g->e4) & $b); $h->e4 = $f->e4 ^ $x;
  96          $x = (($f->e5 ^ $g->e5) & $b); $h->e5 = $f->e5 ^ $x;
  97          $x = (($f->e6 ^ $g->e6) & $b); $h->e6 = $f->e6 ^ $x;
  98          $x = (($f->e7 ^ $g->e7) & $b); $h->e7 = $f->e7 ^ $x;
  99          $x = (($f->e8 ^ $g->e8) & $b); $h->e8 = $f->e8 ^ $x;
 100          $x = (($f->e9 ^ $g->e9) & $b); $h->e9 = $f->e9 ^ $x;
 101          return $h;
 102      }
 103  
 104      /**
 105       * Create a copy of a field element.
 106       *
 107       * @internal You should not use this directly from another application
 108       *
 109       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 110       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 111       */
 112      public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
 113      {
 114          return clone $f;
 115      }
 116  
 117      /**
 118       * Give: 32-byte string.
 119       * Receive: A field element object to use for internal calculations.
 120       *
 121       * @internal You should not use this directly from another application
 122       *
 123       * @param string $s
 124       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 125       * @throws RangeException
 126       * @throws TypeError
 127       */
 128      public static function fe_frombytes($s)
 129      {
 130          if (self::strlen($s) !== 32) {
 131              throw new RangeException('Expected a 32-byte string.');
 132          }
 133          $h0 = self::load_4($s);
 134          $h1 = self::load_3(self::substr($s, 4, 3)) << 6;
 135          $h2 = self::load_3(self::substr($s, 7, 3)) << 5;
 136          $h3 = self::load_3(self::substr($s, 10, 3)) << 3;
 137          $h4 = self::load_3(self::substr($s, 13, 3)) << 2;
 138          $h5 = self::load_4(self::substr($s, 16, 4));
 139          $h6 = self::load_3(self::substr($s, 20, 3)) << 7;
 140          $h7 = self::load_3(self::substr($s, 23, 3)) << 5;
 141          $h8 = self::load_3(self::substr($s, 26, 3)) << 4;
 142          $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2;
 143  
 144          $carry9 = ($h9 + (1 << 24)) >> 25;
 145          $h0 += self::mul($carry9, 19, 5);
 146          $h9 -= $carry9 << 25;
 147          $carry1 = ($h1 + (1 << 24)) >> 25;
 148          $h2 += $carry1;
 149          $h1 -= $carry1 << 25;
 150          $carry3 = ($h3 + (1 << 24)) >> 25;
 151          $h4 += $carry3;
 152          $h3 -= $carry3 << 25;
 153          $carry5 = ($h5 + (1 << 24)) >> 25;
 154          $h6 += $carry5;
 155          $h5 -= $carry5 << 25;
 156          $carry7 = ($h7 + (1 << 24)) >> 25;
 157          $h8 += $carry7;
 158          $h7 -= $carry7 << 25;
 159  
 160          $carry0 = ($h0 + (1 << 25)) >> 26;
 161          $h1 += $carry0;
 162          $h0 -= $carry0 << 26;
 163          $carry2 = ($h2 + (1 << 25)) >> 26;
 164          $h3 += $carry2;
 165          $h2 -= $carry2 << 26;
 166          $carry4 = ($h4 + (1 << 25)) >> 26;
 167          $h5 += $carry4;
 168          $h4 -= $carry4 << 26;
 169          $carry6 = ($h6 + (1 << 25)) >> 26;
 170          $h7 += $carry6;
 171          $h6 -= $carry6 << 26;
 172          $carry8 = ($h8 + (1 << 25)) >> 26;
 173          $h9 += $carry8;
 174          $h8 -= $carry8 << 26;
 175  
 176          return new ParagonIE_Sodium_Core_Curve25519_Fe(
 177              (int) $h0,
 178              (int) $h1,
 179              (int) $h2,
 180              (int) $h3,
 181              (int) $h4,
 182              (int) $h5,
 183              (int) $h6,
 184              (int) $h7,
 185              (int) $h8,
 186              (int) $h9
 187          );
 188      }
 189  
 190      /**
 191       * Convert a field element to a byte string.
 192       *
 193       * @internal You should not use this directly from another application
 194       *
 195       * @param ParagonIE_Sodium_Core_Curve25519_Fe $h
 196       * @return string
 197       */
 198      public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h)
 199      {
 200          $h0 = (int) $h->e0;
 201          $h1 = (int) $h->e1;
 202          $h2 = (int) $h->e2;
 203          $h3 = (int) $h->e3;
 204          $h4 = (int) $h->e4;
 205          $h5 = (int) $h->e5;
 206          $h6 = (int) $h->e6;
 207          $h7 = (int) $h->e7;
 208          $h8 = (int) $h->e8;
 209          $h9 = (int) $h->e9;
 210  
 211          $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
 212          $q = ($h0 + $q) >> 26;
 213          $q = ($h1 + $q) >> 25;
 214          $q = ($h2 + $q) >> 26;
 215          $q = ($h3 + $q) >> 25;
 216          $q = ($h4 + $q) >> 26;
 217          $q = ($h5 + $q) >> 25;
 218          $q = ($h6 + $q) >> 26;
 219          $q = ($h7 + $q) >> 25;
 220          $q = ($h8 + $q) >> 26;
 221          $q = ($h9 + $q) >> 25;
 222  
 223          $h0 += self::mul($q, 19, 5);
 224  
 225          $carry0 = $h0 >> 26;
 226          $h1 += $carry0;
 227          $h0 -= $carry0 << 26;
 228          $carry1 = $h1 >> 25;
 229          $h2 += $carry1;
 230          $h1 -= $carry1 << 25;
 231          $carry2 = $h2 >> 26;
 232          $h3 += $carry2;
 233          $h2 -= $carry2 << 26;
 234          $carry3 = $h3 >> 25;
 235          $h4 += $carry3;
 236          $h3 -= $carry3 << 25;
 237          $carry4 = $h4 >> 26;
 238          $h5 += $carry4;
 239          $h4 -= $carry4 << 26;
 240          $carry5 = $h5 >> 25;
 241          $h6 += $carry5;
 242          $h5 -= $carry5 << 25;
 243          $carry6 = $h6 >> 26;
 244          $h7 += $carry6;
 245          $h6 -= $carry6 << 26;
 246          $carry7 = $h7 >> 25;
 247          $h8 += $carry7;
 248          $h7 -= $carry7 << 25;
 249          $carry8 = $h8 >> 26;
 250          $h9 += $carry8;
 251          $h8 -= $carry8 << 26;
 252          $carry9 = $h9 >> 25;
 253          $h9 -= $carry9 << 25;
 254  
 255          /**
 256           * @var array<int, int>
 257           */
 258          $s = array(
 259              (int) (($h0 >> 0) & 0xff),
 260              (int) (($h0 >> 8) & 0xff),
 261              (int) (($h0 >> 16) & 0xff),
 262              (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
 263              (int) (($h1 >> 6) & 0xff),
 264              (int) (($h1 >> 14) & 0xff),
 265              (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
 266              (int) (($h2 >> 5) & 0xff),
 267              (int) (($h2 >> 13) & 0xff),
 268              (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
 269              (int) (($h3 >> 3) & 0xff),
 270              (int) (($h3 >> 11) & 0xff),
 271              (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
 272              (int) (($h4 >> 2) & 0xff),
 273              (int) (($h4 >> 10) & 0xff),
 274              (int) (($h4 >> 18) & 0xff),
 275              (int) (($h5 >> 0) & 0xff),
 276              (int) (($h5 >> 8) & 0xff),
 277              (int) (($h5 >> 16) & 0xff),
 278              (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
 279              (int) (($h6 >> 7) & 0xff),
 280              (int) (($h6 >> 15) & 0xff),
 281              (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
 282              (int) (($h7 >> 5) & 0xff),
 283              (int) (($h7 >> 13) & 0xff),
 284              (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
 285              (int) (($h8 >> 4) & 0xff),
 286              (int) (($h8 >> 12) & 0xff),
 287              (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
 288              (int) (($h9 >> 2) & 0xff),
 289              (int) (($h9 >> 10) & 0xff),
 290              (int) (($h9 >> 18) & 0xff)
 291          );
 292          return self::intArrayToString($s);
 293      }
 294  
 295      /**
 296       * Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
 297       *
 298       * @internal You should not use this directly from another application
 299       *
 300       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 301       * @return int
 302       * @throws SodiumException
 303       * @throws TypeError
 304       */
 305      public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
 306      {
 307          $str = self::fe_tobytes($f);
 308          return (int) (self::chrToInt($str[0]) & 1);
 309      }
 310  
 311      /**
 312       * Returns 0 if this field element results in all NUL bytes.
 313       *
 314       * @internal You should not use this directly from another application
 315       *
 316       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 317       * @return bool
 318       * @throws SodiumException
 319       * @throws TypeError
 320       */
 321      public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
 322      {
 323          static $zero;
 324          if ($zero === null) {
 325              $zero = str_repeat("\x00", 32);
 326          }
 327          /** @var string $zero */
 328          /** @var string $str */
 329          $str = self::fe_tobytes($f);
 330          return !self::verify_32($str, (string) $zero);
 331      }
 332  
 333      /**
 334       * Multiply two field elements
 335       *
 336       * h = f * g
 337       *
 338       * @internal You should not use this directly from another application
 339       *
 340       * @security Is multiplication a source of timing leaks? If so, can we do
 341       *           anything to prevent that from happening?
 342       *
 343       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 344       * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
 345       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 346       */
 347      public static function fe_mul(
 348          ParagonIE_Sodium_Core_Curve25519_Fe $f,
 349          ParagonIE_Sodium_Core_Curve25519_Fe $g
 350      ) {
 351          // Ensure limbs aren't oversized.
 352          $f = self::fe_normalize($f);
 353          $g = self::fe_normalize($g);
 354          $f0 = $f->e0;
 355          $f1 = $f->e1;
 356          $f2 = $f->e2;
 357          $f3 = $f->e3;
 358          $f4 = $f->e4;
 359          $f5 = $f->e5;
 360          $f6 = $f->e6;
 361          $f7 = $f->e7;
 362          $f8 = $f->e8;
 363          $f9 = $f->e9;
 364          $g0 = $g->e0;
 365          $g1 = $g->e1;
 366          $g2 = $g->e2;
 367          $g3 = $g->e3;
 368          $g4 = $g->e4;
 369          $g5 = $g->e5;
 370          $g6 = $g->e6;
 371          $g7 = $g->e7;
 372          $g8 = $g->e8;
 373          $g9 = $g->e9;
 374          $g1_19 = self::mul($g1, 19, 5);
 375          $g2_19 = self::mul($g2, 19, 5);
 376          $g3_19 = self::mul($g3, 19, 5);
 377          $g4_19 = self::mul($g4, 19, 5);
 378          $g5_19 = self::mul($g5, 19, 5);
 379          $g6_19 = self::mul($g6, 19, 5);
 380          $g7_19 = self::mul($g7, 19, 5);
 381          $g8_19 = self::mul($g8, 19, 5);
 382          $g9_19 = self::mul($g9, 19, 5);
 383          $f1_2 = $f1 << 1;
 384          $f3_2 = $f3 << 1;
 385          $f5_2 = $f5 << 1;
 386          $f7_2 = $f7 << 1;
 387          $f9_2 = $f9 << 1;
 388          $f0g0    = self::mul($f0,    $g0, 26);
 389          $f0g1    = self::mul($f0,    $g1, 25);
 390          $f0g2    = self::mul($f0,    $g2, 26);
 391          $f0g3    = self::mul($f0,    $g3, 25);
 392          $f0g4    = self::mul($f0,    $g4, 26);
 393          $f0g5    = self::mul($f0,    $g5, 25);
 394          $f0g6    = self::mul($f0,    $g6, 26);
 395          $f0g7    = self::mul($f0,    $g7, 25);
 396          $f0g8    = self::mul($f0,    $g8, 26);
 397          $f0g9    = self::mul($f0,    $g9, 26);
 398          $f1g0    = self::mul($f1,    $g0, 26);
 399          $f1g1_2  = self::mul($f1_2,  $g1, 25);
 400          $f1g2    = self::mul($f1,    $g2, 26);
 401          $f1g3_2  = self::mul($f1_2,  $g3, 25);
 402          $f1g4    = self::mul($f1,    $g4, 26);
 403          $f1g5_2  = self::mul($f1_2,  $g5, 25);
 404          $f1g6    = self::mul($f1,    $g6, 26);
 405          $f1g7_2  = self::mul($f1_2,  $g7, 25);
 406          $f1g8    = self::mul($f1,    $g8, 26);
 407          $f1g9_38 = self::mul($g9_19, $f1_2, 26);
 408          $f2g0    = self::mul($f2,    $g0, 26);
 409          $f2g1    = self::mul($f2,    $g1, 25);
 410          $f2g2    = self::mul($f2,    $g2, 26);
 411          $f2g3    = self::mul($f2,    $g3, 25);
 412          $f2g4    = self::mul($f2,    $g4, 26);
 413          $f2g5    = self::mul($f2,    $g5, 25);
 414          $f2g6    = self::mul($f2,    $g6, 26);
 415          $f2g7    = self::mul($f2,    $g7, 25);
 416          $f2g8_19 = self::mul($g8_19, $f2, 26);
 417          $f2g9_19 = self::mul($g9_19, $f2, 26);
 418          $f3g0    = self::mul($f3,    $g0, 26);
 419          $f3g1_2  = self::mul($f3_2,  $g1, 25);
 420          $f3g2    = self::mul($f3,    $g2, 26);
 421          $f3g3_2  = self::mul($f3_2,  $g3, 25);
 422          $f3g4    = self::mul($f3,    $g4, 26);
 423          $f3g5_2  = self::mul($f3_2,  $g5, 25);
 424          $f3g6    = self::mul($f3,    $g6, 26);
 425          $f3g7_38 = self::mul($g7_19, $f3_2, 26);
 426          $f3g8_19 = self::mul($g8_19, $f3, 25);
 427          $f3g9_38 = self::mul($g9_19, $f3_2, 26);
 428          $f4g0    = self::mul($f4,    $g0, 26);
 429          $f4g1    = self::mul($f4,    $g1, 25);
 430          $f4g2    = self::mul($f4,    $g2, 26);
 431          $f4g3    = self::mul($f4,    $g3, 25);
 432          $f4g4    = self::mul($f4,    $g4, 26);
 433          $f4g5    = self::mul($f4,    $g5, 25);
 434          $f4g6_19 = self::mul($g6_19, $f4, 26);
 435          $f4g7_19 = self::mul($g7_19, $f4, 26);
 436          $f4g8_19 = self::mul($g8_19, $f4, 26);
 437          $f4g9_19 = self::mul($g9_19, $f4, 26);
 438          $f5g0    = self::mul($f5,    $g0, 26);
 439          $f5g1_2  = self::mul($f5_2,  $g1, 25);
 440          $f5g2    = self::mul($f5,    $g2, 26);
 441          $f5g3_2  = self::mul($f5_2,  $g3, 25);
 442          $f5g4    = self::mul($f5,    $g4, 26);
 443          $f5g5_38 = self::mul($g5_19, $f5_2, 26);
 444          $f5g6_19 = self::mul($g6_19, $f5, 25);
 445          $f5g7_38 = self::mul($g7_19, $f5_2, 26);
 446          $f5g8_19 = self::mul($g8_19, $f5, 25);
 447          $f5g9_38 = self::mul($g9_19, $f5_2, 26);
 448          $f6g0    = self::mul($f6,    $g0, 26);
 449          $f6g1    = self::mul($f6,    $g1, 25);
 450          $f6g2    = self::mul($f6,    $g2, 26);
 451          $f6g3    = self::mul($f6,    $g3, 25);
 452          $f6g4_19 = self::mul($g4_19, $f6, 26);
 453          $f6g5_19 = self::mul($g5_19, $f6, 26);
 454          $f6g6_19 = self::mul($g6_19, $f6, 26);
 455          $f6g7_19 = self::mul($g7_19, $f6, 26);
 456          $f6g8_19 = self::mul($g8_19, $f6, 26);
 457          $f6g9_19 = self::mul($g9_19, $f6, 26);
 458          $f7g0    = self::mul($f7,    $g0, 26);
 459          $f7g1_2  = self::mul($f7_2,  $g1, 25);
 460          $f7g2    = self::mul($f7,    $g2, 26);
 461          $f7g3_38 = self::mul($g3_19, $f7_2, 26);
 462          $f7g4_19 = self::mul($g4_19, $f7, 26);
 463          $f7g5_38 = self::mul($g5_19, $f7_2, 26);
 464          $f7g6_19 = self::mul($g6_19, $f7, 25);
 465          $f7g7_38 = self::mul($g7_19, $f7_2, 26);
 466          $f7g8_19 = self::mul($g8_19, $f7, 25);
 467          $f7g9_38 = self::mul($g9_19,$f7_2, 26);
 468          $f8g0    = self::mul($f8,    $g0, 26);
 469          $f8g1    = self::mul($f8,    $g1, 25);
 470          $f8g2_19 = self::mul($g2_19, $f8, 26);
 471          $f8g3_19 = self::mul($g3_19, $f8, 26);
 472          $f8g4_19 = self::mul($g4_19, $f8, 26);
 473          $f8g5_19 = self::mul($g5_19, $f8, 26);
 474          $f8g6_19 = self::mul($g6_19, $f8, 26);
 475          $f8g7_19 = self::mul($g7_19, $f8, 26);
 476          $f8g8_19 = self::mul($g8_19, $f8, 26);
 477          $f8g9_19 = self::mul($g9_19, $f8, 26);
 478          $f9g0    = self::mul($f9,    $g0, 26);
 479          $f9g1_38 = self::mul($g1_19, $f9_2, 26);
 480          $f9g2_19 = self::mul($g2_19, $f9, 25);
 481          $f9g3_38 = self::mul($g3_19, $f9_2, 26);
 482          $f9g4_19 = self::mul($g4_19, $f9, 25);
 483          $f9g5_38 = self::mul($g5_19, $f9_2, 26);
 484          $f9g6_19 = self::mul($g6_19, $f9, 25);
 485          $f9g7_38 = self::mul($g7_19, $f9_2, 26);
 486          $f9g8_19 = self::mul($g8_19, $f9, 25);
 487          $f9g9_38 = self::mul($g9_19, $f9_2, 26);
 488  
 489          $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
 490          $h1 = $f0g1 + $f1g0    + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
 491          $h2 = $f0g2 + $f1g1_2  + $f2g0    + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
 492          $h3 = $f0g3 + $f1g2    + $f2g1    + $f3g0    + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
 493          $h4 = $f0g4 + $f1g3_2  + $f2g2    + $f3g1_2  + $f4g0    + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
 494          $h5 = $f0g5 + $f1g4    + $f2g3    + $f3g2    + $f4g1    + $f5g0    + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
 495          $h6 = $f0g6 + $f1g5_2  + $f2g4    + $f3g3_2  + $f4g2    + $f5g1_2  + $f6g0    + $f7g9_38 + $f8g8_19 + $f9g7_38;
 496          $h7 = $f0g7 + $f1g6    + $f2g5    + $f3g4    + $f4g3    + $f5g2    + $f6g1    + $f7g0    + $f8g9_19 + $f9g8_19;
 497          $h8 = $f0g8 + $f1g7_2  + $f2g6    + $f3g5_2  + $f4g4    + $f5g3_2  + $f6g2    + $f7g1_2  + $f8g0    + $f9g9_38;
 498          $h9 = $f0g9 + $f1g8    + $f2g7    + $f3g6    + $f4g5    + $f5g4    + $f6g3    + $f7g2    + $f8g1    + $f9g0   ;
 499  
 500          $carry0 = ($h0 + (1 << 25)) >> 26;
 501          $h1 += $carry0;
 502          $h0 -= $carry0 << 26;
 503          $carry4 = ($h4 + (1 << 25)) >> 26;
 504          $h5 += $carry4;
 505          $h4 -= $carry4 << 26;
 506  
 507          $carry1 = ($h1 + (1 << 24)) >> 25;
 508          $h2 += $carry1;
 509          $h1 -= $carry1 << 25;
 510          $carry5 = ($h5 + (1 << 24)) >> 25;
 511          $h6 += $carry5;
 512          $h5 -= $carry5 << 25;
 513  
 514          $carry2 = ($h2 + (1 << 25)) >> 26;
 515          $h3 += $carry2;
 516          $h2 -= $carry2 << 26;
 517          $carry6 = ($h6 + (1 << 25)) >> 26;
 518          $h7 += $carry6;
 519          $h6 -= $carry6 << 26;
 520  
 521          $carry3 = ($h3 + (1 << 24)) >> 25;
 522          $h4 += $carry3;
 523          $h3 -= $carry3 << 25;
 524          $carry7 = ($h7 + (1 << 24)) >> 25;
 525          $h8 += $carry7;
 526          $h7 -= $carry7 << 25;
 527  
 528          $carry4 = ($h4 + (1 << 25)) >> 26;
 529          $h5 += $carry4;
 530          $h4 -= $carry4 << 26;
 531          $carry8 = ($h8 + (1 << 25)) >> 26;
 532          $h9 += $carry8;
 533          $h8 -= $carry8 << 26;
 534  
 535          $carry9 = ($h9 + (1 << 24)) >> 25;
 536          $h0 += self::mul($carry9, 19, 5);
 537          $h9 -= $carry9 << 25;
 538  
 539          $carry0 = ($h0 + (1 << 25)) >> 26;
 540          $h1 += $carry0;
 541          $h0 -= $carry0 << 26;
 542  
 543          return self::fe_normalize(
 544              new ParagonIE_Sodium_Core_Curve25519_Fe(
 545                  (int) $h0,
 546                  (int) $h1,
 547                  (int) $h2,
 548                  (int) $h3,
 549                  (int) $h4,
 550                  (int) $h5,
 551                  (int) $h6,
 552                  (int) $h7,
 553                  (int) $h8,
 554                  (int) $h9
 555              )
 556          );
 557      }
 558  
 559      /**
 560       * Get the negative values for each piece of the field element.
 561       *
 562       * h = -f
 563       *
 564       * @internal You should not use this directly from another application
 565       *
 566       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 567       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 568       * @psalm-suppress MixedAssignment
 569       */
 570      public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
 571      {
 572          return self::fe_normalize(
 573              new ParagonIE_Sodium_Core_Curve25519_Fe(
 574                  -$f->e0,
 575                  -$f->e1,
 576                  -$f->e2,
 577                  -$f->e3,
 578                  -$f->e4,
 579                  -$f->e5,
 580                  -$f->e6,
 581                  -$f->e7,
 582                  -$f->e8,
 583                  -$f->e9
 584              )
 585          );
 586      }
 587  
 588      /**
 589       * Square a field element
 590       *
 591       * h = f * f
 592       *
 593       * @internal You should not use this directly from another application
 594       *
 595       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 596       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 597       */
 598      public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
 599      {
 600          $f = self::fe_normalize($f);
 601          $f0 = (int) $f->e0;
 602          $f1 = (int) $f->e1;
 603          $f2 = (int) $f->e2;
 604          $f3 = (int) $f->e3;
 605          $f4 = (int) $f->e4;
 606          $f5 = (int) $f->e5;
 607          $f6 = (int) $f->e6;
 608          $f7 = (int) $f->e7;
 609          $f8 = (int) $f->e8;
 610          $f9 = (int) $f->e9;
 611  
 612          $f0_2 = $f0 << 1;
 613          $f1_2 = $f1 << 1;
 614          $f2_2 = $f2 << 1;
 615          $f3_2 = $f3 << 1;
 616          $f4_2 = $f4 << 1;
 617          $f5_2 = $f5 << 1;
 618          $f6_2 = $f6 << 1;
 619          $f7_2 = $f7 << 1;
 620          $f5_38 = self::mul($f5, 38, 6);
 621          $f6_19 = self::mul($f6, 19, 5);
 622          $f7_38 = self::mul($f7, 38, 6);
 623          $f8_19 = self::mul($f8, 19, 5);
 624          $f9_38 = self::mul($f9, 38, 6);
 625          $f0f0    = self::mul($f0,    $f0,    26);
 626          $f0f1_2  = self::mul($f0_2,  $f1,    26);
 627          $f0f2_2  = self::mul($f0_2,  $f2,    26);
 628          $f0f3_2  = self::mul($f0_2,  $f3,    26);
 629          $f0f4_2  = self::mul($f0_2,  $f4,    26);
 630          $f0f5_2  = self::mul($f0_2,  $f5,    26);
 631          $f0f6_2  = self::mul($f0_2,  $f6,    26);
 632          $f0f7_2  = self::mul($f0_2,  $f7,    26);
 633          $f0f8_2  = self::mul($f0_2,  $f8,    26);
 634          $f0f9_2  = self::mul($f0_2,  $f9,    26);
 635          $f1f1_2  = self::mul($f1_2,  $f1,    26);
 636          $f1f2_2  = self::mul($f1_2,  $f2,    26);
 637          $f1f3_4  = self::mul($f1_2,  $f3_2,  26);
 638          $f1f4_2  = self::mul($f1_2,  $f4,    26);
 639          $f1f5_4  = self::mul($f1_2,  $f5_2,  26);
 640          $f1f6_2  = self::mul($f1_2,  $f6,    26);
 641          $f1f7_4  = self::mul($f1_2,  $f7_2,  26);
 642          $f1f8_2  = self::mul($f1_2,  $f8,    26);
 643          $f1f9_76 = self::mul($f9_38, $f1_2,  27);
 644          $f2f2    = self::mul($f2,    $f2,    27);
 645          $f2f3_2  = self::mul($f2_2,  $f3,    27);
 646          $f2f4_2  = self::mul($f2_2,  $f4,    27);
 647          $f2f5_2  = self::mul($f2_2,  $f5,    27);
 648          $f2f6_2  = self::mul($f2_2,  $f6,    27);
 649          $f2f7_2  = self::mul($f2_2,  $f7,    27);
 650          $f2f8_38 = self::mul($f8_19, $f2_2,  27);
 651          $f2f9_38 = self::mul($f9_38, $f2,    26);
 652          $f3f3_2  = self::mul($f3_2,  $f3,    26);
 653          $f3f4_2  = self::mul($f3_2,  $f4,    26);
 654          $f3f5_4  = self::mul($f3_2,  $f5_2,  26);
 655          $f3f6_2  = self::mul($f3_2,  $f6,    26);
 656          $f3f7_76 = self::mul($f7_38, $f3_2,  26);
 657          $f3f8_38 = self::mul($f8_19, $f3_2,  26);
 658          $f3f9_76 = self::mul($f9_38, $f3_2,  26);
 659          $f4f4    = self::mul($f4,    $f4,    26);
 660          $f4f5_2  = self::mul($f4_2,  $f5,    26);
 661          $f4f6_38 = self::mul($f6_19, $f4_2,  27);
 662          $f4f7_38 = self::mul($f7_38, $f4,    26);
 663          $f4f8_38 = self::mul($f8_19, $f4_2,  27);
 664          $f4f9_38 = self::mul($f9_38, $f4,    26);
 665          $f5f5_38 = self::mul($f5_38, $f5,    26);
 666          $f5f6_38 = self::mul($f6_19, $f5_2,  26);
 667          $f5f7_76 = self::mul($f7_38, $f5_2,  26);
 668          $f5f8_38 = self::mul($f8_19, $f5_2,  26);
 669          $f5f9_76 = self::mul($f9_38, $f5_2,  26);
 670          $f6f6_19 = self::mul($f6_19, $f6,    26);
 671          $f6f7_38 = self::mul($f7_38, $f6,    26);
 672          $f6f8_38 = self::mul($f8_19, $f6_2,  27);
 673          $f6f9_38 = self::mul($f9_38, $f6,    26);
 674          $f7f7_38 = self::mul($f7_38, $f7,    26);
 675          $f7f8_38 = self::mul($f8_19, $f7_2,  26);
 676          $f7f9_76 = self::mul($f9_38, $f7_2,  26);
 677          $f8f8_19 = self::mul($f8_19, $f8,    26);
 678          $f8f9_38 = self::mul($f9_38, $f8,    26);
 679          $f9f9_38 = self::mul($f9_38, $f9,    26);
 680          $h0 = $f0f0   + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38;
 681          $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
 682          $h2 = $f0f2_2 + $f1f1_2  + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19;
 683          $h3 = $f0f3_2 + $f1f2_2  + $f4f9_38 + $f5f8_38 + $f6f7_38;
 684          $h4 = $f0f4_2 + $f1f3_4  + $f2f2    + $f5f9_76 + $f6f8_38 + $f7f7_38;
 685          $h5 = $f0f5_2 + $f1f4_2  + $f2f3_2  + $f6f9_38 + $f7f8_38;
 686          $h6 = $f0f6_2 + $f1f5_4  + $f2f4_2  + $f3f3_2  + $f7f9_76 + $f8f8_19;
 687          $h7 = $f0f7_2 + $f1f6_2  + $f2f5_2  + $f3f4_2  + $f8f9_38;
 688          $h8 = $f0f8_2 + $f1f7_4  + $f2f6_2  + $f3f5_4  + $f4f4    + $f9f9_38;
 689          $h9 = $f0f9_2 + $f1f8_2  + $f2f7_2  + $f3f6_2  + $f4f5_2;
 690  
 691          $carry0 = ($h0 + (1 << 25)) >> 26;
 692          $h1 += $carry0;
 693          $h0 -= $carry0 << 26;
 694          $carry4 = ($h4 + (1 << 25)) >> 26;
 695          $h5 += $carry4;
 696          $h4 -= $carry4 << 26;
 697  
 698          $carry1 = ($h1 + (1 << 24)) >> 25;
 699          $h2 += $carry1;
 700          $h1 -= $carry1 << 25;
 701          $carry5 = ($h5 + (1 << 24)) >> 25;
 702          $h6 += $carry5;
 703          $h5 -= $carry5 << 25;
 704  
 705          $carry2 = ($h2 + (1 << 25)) >> 26;
 706          $h3 += $carry2;
 707          $h2 -= $carry2 << 26;
 708          $carry6 = ($h6 + (1 << 25)) >> 26;
 709          $h7 += $carry6;
 710          $h6 -= $carry6 << 26;
 711  
 712          $carry3 = ($h3 + (1 << 24)) >> 25;
 713          $h4 += $carry3;
 714          $h3 -= $carry3 << 25;
 715          $carry7 = ($h7 + (1 << 24)) >> 25;
 716          $h8 += $carry7;
 717          $h7 -= $carry7 << 25;
 718  
 719          $carry4 = ($h4 + (1 << 25)) >> 26;
 720          $h5 += $carry4;
 721          $h4 -= $carry4 << 26;
 722          $carry8 = ($h8 + (1 << 25)) >> 26;
 723          $h9 += $carry8;
 724          $h8 -= $carry8 << 26;
 725  
 726          $carry9 = ($h9 + (1 << 24)) >> 25;
 727          $h0 += self::mul($carry9, 19, 5);
 728          $h9 -= $carry9 << 25;
 729  
 730          $carry0 = ($h0 + (1 << 25)) >> 26;
 731          $h1 += $carry0;
 732          $h0 -= $carry0 << 26;
 733  
 734          return self::fe_normalize(
 735              new ParagonIE_Sodium_Core_Curve25519_Fe(
 736                  (int) $h0,
 737                  (int) $h1,
 738                  (int) $h2,
 739                  (int) $h3,
 740                  (int) $h4,
 741                  (int) $h5,
 742                  (int) $h6,
 743                  (int) $h7,
 744                  (int) $h8,
 745                  (int) $h9
 746              )
 747          );
 748      }
 749  
 750  
 751      /**
 752       * Square and double a field element
 753       *
 754       * h = 2 * f * f
 755       *
 756       * @internal You should not use this directly from another application
 757       *
 758       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
 759       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 760       */
 761      public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
 762      {
 763          $f = self::fe_normalize($f);
 764          $f0 = (int) $f->e0;
 765          $f1 = (int) $f->e1;
 766          $f2 = (int) $f->e2;
 767          $f3 = (int) $f->e3;
 768          $f4 = (int) $f->e4;
 769          $f5 = (int) $f->e5;
 770          $f6 = (int) $f->e6;
 771          $f7 = (int) $f->e7;
 772          $f8 = (int) $f->e8;
 773          $f9 = (int) $f->e9;
 774  
 775          $f0_2 = $f0 << 1;
 776          $f1_2 = $f1 << 1;
 777          $f2_2 = $f2 << 1;
 778          $f3_2 = $f3 << 1;
 779          $f4_2 = $f4 << 1;
 780          $f5_2 = $f5 << 1;
 781          $f6_2 = $f6 << 1;
 782          $f7_2 = $f7 << 1;
 783          $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
 784          $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
 785          $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
 786          $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
 787          $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
 788          $f0f0 = self::mul($f0, $f0, 24);
 789          $f0f1_2 = self::mul($f0_2, $f1, 24);
 790          $f0f2_2 = self::mul($f0_2, $f2, 24);
 791          $f0f3_2 = self::mul($f0_2, $f3, 24);
 792          $f0f4_2 = self::mul($f0_2, $f4, 24);
 793          $f0f5_2 = self::mul($f0_2, $f5, 24);
 794          $f0f6_2 = self::mul($f0_2, $f6, 24);
 795          $f0f7_2 = self::mul($f0_2, $f7, 24);
 796          $f0f8_2 = self::mul($f0_2, $f8, 24);
 797          $f0f9_2 = self::mul($f0_2, $f9, 24);
 798          $f1f1_2 = self::mul($f1_2,  $f1, 24);
 799          $f1f2_2 = self::mul($f1_2,  $f2, 24);
 800          $f1f3_4 = self::mul($f1_2,  $f3_2, 24);
 801          $f1f4_2 = self::mul($f1_2,  $f4, 24);
 802          $f1f5_4 = self::mul($f1_2,  $f5_2, 24);
 803          $f1f6_2 = self::mul($f1_2,  $f6, 24);
 804          $f1f7_4 = self::mul($f1_2,  $f7_2, 24);
 805          $f1f8_2 = self::mul($f1_2,  $f8, 24);
 806          $f1f9_76 = self::mul($f9_38, $f1_2, 24);
 807          $f2f2 = self::mul($f2,  $f2, 24);
 808          $f2f3_2 = self::mul($f2_2,  $f3, 24);
 809          $f2f4_2 = self::mul($f2_2,  $f4, 24);
 810          $f2f5_2 = self::mul($f2_2,  $f5, 24);
 811          $f2f6_2 = self::mul($f2_2,  $f6, 24);
 812          $f2f7_2 = self::mul($f2_2,  $f7, 24);
 813          $f2f8_38 = self::mul($f8_19, $f2_2, 25);
 814          $f2f9_38 = self::mul($f9_38, $f2, 24);
 815          $f3f3_2 = self::mul($f3_2,  $f3, 24);
 816          $f3f4_2 = self::mul($f3_2,  $f4, 24);
 817          $f3f5_4 = self::mul($f3_2,  $f5_2, 24);
 818          $f3f6_2 = self::mul($f3_2,  $f6, 24);
 819          $f3f7_76 = self::mul($f7_38, $f3_2, 24);
 820          $f3f8_38 = self::mul($f8_19, $f3_2, 24);
 821          $f3f9_76 = self::mul($f9_38, $f3_2, 24);
 822          $f4f4 = self::mul($f4,  $f4, 24);
 823          $f4f5_2 = self::mul($f4_2,  $f5, 24);
 824          $f4f6_38 = self::mul($f6_19, $f4_2, 25);
 825          $f4f7_38 = self::mul($f7_38, $f4, 24);
 826          $f4f8_38 = self::mul($f8_19, $f4_2, 25);
 827          $f4f9_38 = self::mul($f9_38, $f4, 24);
 828          $f5f5_38 = self::mul($f5_38, $f5, 24);
 829          $f5f6_38 = self::mul($f6_19, $f5_2, 24);
 830          $f5f7_76 = self::mul($f7_38, $f5_2, 24);
 831          $f5f8_38 = self::mul($f8_19, $f5_2, 24);
 832          $f5f9_76 = self::mul($f9_38, $f5_2, 24);
 833          $f6f6_19 = self::mul($f6_19, $f6, 24);
 834          $f6f7_38 = self::mul($f7_38, $f6, 24);
 835          $f6f8_38 = self::mul($f8_19, $f6_2, 25);
 836          $f6f9_38 = self::mul($f9_38, $f6, 24);
 837          $f7f7_38 = self::mul($f7_38, $f7, 24);
 838          $f7f8_38 = self::mul($f8_19, $f7_2, 24);
 839          $f7f9_76 = self::mul($f9_38, $f7_2, 24);
 840          $f8f8_19 = self::mul($f8_19, $f8, 24);
 841          $f8f9_38 = self::mul($f9_38, $f8, 24);
 842          $f9f9_38 = self::mul($f9_38, $f9, 24);
 843  
 844          $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1;
 845          $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1;
 846          $h2 = (int) ($f0f2_2 + $f1f1_2  + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1;
 847          $h3 = (int) ($f0f3_2 + $f1f2_2  + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1;
 848          $h4 = (int) ($f0f4_2 + $f1f3_4  + $f2f2    + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1;
 849          $h5 = (int) ($f0f5_2 + $f1f4_2  + $f2f3_2  + $f6f9_38 + $f7f8_38) << 1;
 850          $h6 = (int) ($f0f6_2 + $f1f5_4  + $f2f4_2  + $f3f3_2  + $f7f9_76 + $f8f8_19) << 1;
 851          $h7 = (int) ($f0f7_2 + $f1f6_2  + $f2f5_2  + $f3f4_2  + $f8f9_38) << 1;
 852          $h8 = (int) ($f0f8_2 + $f1f7_4  + $f2f6_2  + $f3f5_4  + $f4f4    + $f9f9_38) << 1;
 853          $h9 = (int) ($f0f9_2 + $f1f8_2  + $f2f7_2  + $f3f6_2  + $f4f5_2) << 1;
 854  
 855          $carry0 = ($h0 + (1 << 25)) >> 26;
 856          $h1 += $carry0;
 857          $h0 -= $carry0 << 26;
 858          $carry4 = ($h4 + (1 << 25)) >> 26;
 859          $h5 += $carry4;
 860          $h4 -= $carry4 << 26;
 861  
 862          $carry1 = ($h1 + (1 << 24)) >> 25;
 863          $h2 += $carry1;
 864          $h1 -= $carry1 << 25;
 865          $carry5 = ($h5 + (1 << 24)) >> 25;
 866          $h6 += $carry5;
 867          $h5 -= $carry5 << 25;
 868  
 869          $carry2 = ($h2 + (1 << 25)) >> 26;
 870          $h3 += $carry2;
 871          $h2 -= $carry2 << 26;
 872          $carry6 = ($h6 + (1 << 25)) >> 26;
 873          $h7 += $carry6;
 874          $h6 -= $carry6 << 26;
 875  
 876          $carry3 = ($h3 + (1 << 24)) >> 25;
 877          $h4 += $carry3;
 878          $h3 -= $carry3 << 25;
 879          $carry7 = ($h7 + (1 << 24)) >> 25;
 880          $h8 += $carry7;
 881          $h7 -= $carry7 << 25;
 882  
 883          $carry4 = ($h4 + (1 << 25)) >> 26;
 884          $h5 += $carry4;
 885          $h4 -= $carry4 << 26;
 886          $carry8 = ($h8 + (1 << 25)) >> 26;
 887          $h9 += $carry8;
 888          $h8 -= $carry8 << 26;
 889  
 890          $carry9 = ($h9 + (1 << 24)) >> 25;
 891          $h0 += self::mul($carry9, 19, 5);
 892          $h9 -= $carry9 << 25;
 893  
 894          $carry0 = ($h0 + (1 << 25)) >> 26;
 895          $h1 += $carry0;
 896          $h0 -= $carry0 << 26;
 897  
 898          return self::fe_normalize(
 899              new ParagonIE_Sodium_Core_Curve25519_Fe(
 900                  (int) $h0,
 901                  (int) $h1,
 902                  (int) $h2,
 903                  (int) $h3,
 904                  (int) $h4,
 905                  (int) $h5,
 906                  (int) $h6,
 907                  (int) $h7,
 908                  (int) $h8,
 909                  (int) $h9
 910              )
 911          );
 912      }
 913  
 914      /**
 915       * @internal You should not use this directly from another application
 916       *
 917       * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
 918       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 919       */
 920      public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z)
 921      {
 922          $z = clone $Z;
 923          $t0 = self::fe_sq($z);
 924          $t1 = self::fe_sq($t0);
 925          $t1 = self::fe_sq($t1);
 926          $t1 = self::fe_mul($z, $t1);
 927          $t0 = self::fe_mul($t0, $t1);
 928          $t2 = self::fe_sq($t0);
 929          $t1 = self::fe_mul($t1, $t2);
 930          $t2 = self::fe_sq($t1);
 931          for ($i = 1; $i < 5; ++$i) {
 932              $t2 = self::fe_sq($t2);
 933          }
 934          $t1 = self::fe_mul($t2, $t1);
 935          $t2 = self::fe_sq($t1);
 936          for ($i = 1; $i < 10; ++$i) {
 937              $t2 = self::fe_sq($t2);
 938          }
 939          $t2 = self::fe_mul($t2, $t1);
 940          $t3 = self::fe_sq($t2);
 941          for ($i = 1; $i < 20; ++$i) {
 942              $t3 = self::fe_sq($t3);
 943          }
 944          $t2 = self::fe_mul($t3, $t2);
 945          $t2 = self::fe_sq($t2);
 946          for ($i = 1; $i < 10; ++$i) {
 947              $t2 = self::fe_sq($t2);
 948          }
 949          $t1 = self::fe_mul($t2, $t1);
 950          $t2 = self::fe_sq($t1);
 951          for ($i = 1; $i < 50; ++$i) {
 952              $t2 = self::fe_sq($t2);
 953          }
 954          $t2 = self::fe_mul($t2, $t1);
 955          $t3 = self::fe_sq($t2);
 956          for ($i = 1; $i < 100; ++$i) {
 957              $t3 = self::fe_sq($t3);
 958          }
 959          $t2 = self::fe_mul($t3, $t2);
 960          $t2 = self::fe_sq($t2);
 961          for ($i = 1; $i < 50; ++$i) {
 962              $t2 = self::fe_sq($t2);
 963          }
 964          $t1 = self::fe_mul($t2, $t1);
 965          $t1 = self::fe_sq($t1);
 966          for ($i = 1; $i < 5; ++$i) {
 967              $t1 = self::fe_sq($t1);
 968          }
 969          return self::fe_mul($t1, $t0);
 970      }
 971  
 972      /**
 973       * @internal You should not use this directly from another application
 974       *
 975       * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
 976       *
 977       * @param ParagonIE_Sodium_Core_Curve25519_Fe $z
 978       * @return ParagonIE_Sodium_Core_Curve25519_Fe
 979       */
 980      public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z)
 981      {
 982          $z = self::fe_normalize($z);
 983          # fe_sq(t0, z);
 984          # fe_sq(t1, t0);
 985          # fe_sq(t1, t1);
 986          # fe_mul(t1, z, t1);
 987          # fe_mul(t0, t0, t1);
 988          # fe_sq(t0, t0);
 989          # fe_mul(t0, t1, t0);
 990          # fe_sq(t1, t0);
 991          $t0 = self::fe_sq($z);
 992          $t1 = self::fe_sq($t0);
 993          $t1 = self::fe_sq($t1);
 994          $t1 = self::fe_mul($z, $t1);
 995          $t0 = self::fe_mul($t0, $t1);
 996          $t0 = self::fe_sq($t0);
 997          $t0 = self::fe_mul($t1, $t0);
 998          $t1 = self::fe_sq($t0);
 999  
1000          # for (i = 1; i < 5; ++i) {
1001          #     fe_sq(t1, t1);
1002          # }
1003          for ($i = 1; $i < 5; ++$i) {
1004              $t1 = self::fe_sq($t1);
1005          }
1006  
1007          # fe_mul(t0, t1, t0);
1008          # fe_sq(t1, t0);
1009          $t0 = self::fe_mul($t1, $t0);
1010          $t1 = self::fe_sq($t0);
1011  
1012          # for (i = 1; i < 10; ++i) {
1013          #     fe_sq(t1, t1);
1014          # }
1015          for ($i = 1; $i < 10; ++$i) {
1016              $t1 = self::fe_sq($t1);
1017          }
1018  
1019          # fe_mul(t1, t1, t0);
1020          # fe_sq(t2, t1);
1021          $t1 = self::fe_mul($t1, $t0);
1022          $t2 = self::fe_sq($t1);
1023  
1024          # for (i = 1; i < 20; ++i) {
1025          #     fe_sq(t2, t2);
1026          # }
1027          for ($i = 1; $i < 20; ++$i) {
1028              $t2 = self::fe_sq($t2);
1029          }
1030  
1031          # fe_mul(t1, t2, t1);
1032          # fe_sq(t1, t1);
1033          $t1 = self::fe_mul($t2, $t1);
1034          $t1 = self::fe_sq($t1);
1035  
1036          # for (i = 1; i < 10; ++i) {
1037          #     fe_sq(t1, t1);
1038          # }
1039          for ($i = 1; $i < 10; ++$i) {
1040              $t1 = self::fe_sq($t1);
1041          }
1042  
1043          # fe_mul(t0, t1, t0);
1044          # fe_sq(t1, t0);
1045          $t0 = self::fe_mul($t1, $t0);
1046          $t1 = self::fe_sq($t0);
1047  
1048          # for (i = 1; i < 50; ++i) {
1049          #     fe_sq(t1, t1);
1050          # }
1051          for ($i = 1; $i < 50; ++$i) {
1052              $t1 = self::fe_sq($t1);
1053          }
1054  
1055          # fe_mul(t1, t1, t0);
1056          # fe_sq(t2, t1);
1057          $t1 = self::fe_mul($t1, $t0);
1058          $t2 = self::fe_sq($t1);
1059  
1060          # for (i = 1; i < 100; ++i) {
1061          #     fe_sq(t2, t2);
1062          # }
1063          for ($i = 1; $i < 100; ++$i) {
1064              $t2 = self::fe_sq($t2);
1065          }
1066  
1067          # fe_mul(t1, t2, t1);
1068          # fe_sq(t1, t1);
1069          $t1 = self::fe_mul($t2, $t1);
1070          $t1 = self::fe_sq($t1);
1071  
1072          # for (i = 1; i < 50; ++i) {
1073          #     fe_sq(t1, t1);
1074          # }
1075          for ($i = 1; $i < 50; ++$i) {
1076              $t1 = self::fe_sq($t1);
1077          }
1078  
1079          # fe_mul(t0, t1, t0);
1080          # fe_sq(t0, t0);
1081          # fe_sq(t0, t0);
1082          # fe_mul(out, t0, z);
1083          $t0 = self::fe_mul($t1, $t0);
1084          $t0 = self::fe_sq($t0);
1085          $t0 = self::fe_sq($t0);
1086          return self::fe_mul($t0, $z);
1087      }
1088  
1089      /**
1090       * Subtract two field elements.
1091       *
1092       * h = f - g
1093       *
1094       * Preconditions:
1095       * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
1096       * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
1097       *
1098       * Postconditions:
1099       * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
1100       *
1101       * @internal You should not use this directly from another application
1102       *
1103       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
1104       * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
1105       * @return ParagonIE_Sodium_Core_Curve25519_Fe
1106       * @psalm-suppress MixedOperand
1107       */
1108      public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g)
1109      {
1110          return self::fe_normalize(
1111              new ParagonIE_Sodium_Core_Curve25519_Fe(
1112                  (int) ($f->e0 - $g->e0),
1113                  (int) ($f->e1 - $g->e1),
1114                  (int) ($f->e2 - $g->e2),
1115                  (int) ($f->e3 - $g->e3),
1116                  (int) ($f->e4 - $g->e4),
1117                  (int) ($f->e5 - $g->e5),
1118                  (int) ($f->e6 - $g->e6),
1119                  (int) ($f->e7 - $g->e7),
1120                  (int) ($f->e8 - $g->e8),
1121                  (int) ($f->e9 - $g->e9)
1122              )
1123          );
1124      }
1125  
1126      /**
1127       * Add two group elements.
1128       *
1129       * r = p + q
1130       *
1131       * @internal You should not use this directly from another application
1132       *
1133       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1134       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
1135       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
1136       */
1137      public static function ge_add(
1138          ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
1139          ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
1140      ) {
1141          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
1142          $r->X = self::fe_add($p->Y, $p->X);
1143          $r->Y = self::fe_sub($p->Y, $p->X);
1144          $r->Z = self::fe_mul($r->X, $q->YplusX);
1145          $r->Y = self::fe_mul($r->Y, $q->YminusX);
1146          $r->T = self::fe_mul($q->T2d, $p->T);
1147          $r->X = self::fe_mul($p->Z, $q->Z);
1148          $t0   = self::fe_add($r->X, $r->X);
1149          $r->X = self::fe_sub($r->Z, $r->Y);
1150          $r->Y = self::fe_add($r->Z, $r->Y);
1151          $r->Z = self::fe_add($t0, $r->T);
1152          $r->T = self::fe_sub($t0, $r->T);
1153          return $r;
1154      }
1155  
1156      /**
1157       * @internal You should not use this directly from another application
1158       *
1159       * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
1160       * @param string $a
1161       * @return array<int, mixed>
1162       * @throws SodiumException
1163       * @throws TypeError
1164       */
1165      public static function slide($a)
1166      {
1167          if (self::strlen($a) < 256) {
1168              if (self::strlen($a) < 16) {
1169                  $a = str_pad($a, 256, '0', STR_PAD_RIGHT);
1170              }
1171          }
1172          /** @var array<int, int> $r */
1173          $r = array();
1174  
1175          /** @var int $i */
1176          for ($i = 0; $i < 256; ++$i) {
1177              $r[$i] = (int) (
1178                  1 & (
1179                      self::chrToInt($a[(int) ($i >> 3)])
1180                          >>
1181                      ($i & 7)
1182                  )
1183              );
1184          }
1185  
1186          for ($i = 0;$i < 256;++$i) {
1187              if ($r[$i]) {
1188                  for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
1189                      if ($r[$i + $b]) {
1190                          if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
1191                              $r[$i] += $r[$i + $b] << $b;
1192                              $r[$i + $b] = 0;
1193                          } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
1194                              $r[$i] -= $r[$i + $b] << $b;
1195                              for ($k = $i + $b; $k < 256; ++$k) {
1196                                  if (!$r[$k]) {
1197                                      $r[$k] = 1;
1198                                      break;
1199                                  }
1200                                  $r[$k] = 0;
1201                              }
1202                          } else {
1203                              break;
1204                          }
1205                      }
1206                  }
1207              }
1208          }
1209          return $r;
1210      }
1211  
1212      /**
1213       * @internal You should not use this directly from another application
1214       *
1215       * @param string $s
1216       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
1217       * @throws SodiumException
1218       * @throws TypeError
1219       */
1220      public static function ge_frombytes_negate_vartime($s)
1221      {
1222          static $d = null;
1223          if (!$d) {
1224              $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
1225          }
1226  
1227          # fe_frombytes(h->Y,s);
1228          # fe_1(h->Z);
1229          $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
1230              self::fe_0(),
1231              self::fe_frombytes($s),
1232              self::fe_1()
1233          );
1234  
1235          # fe_sq(u,h->Y);
1236          # fe_mul(v,u,d);
1237          # fe_sub(u,u,h->Z);       /* u = y^2-1 */
1238          # fe_add(v,v,h->Z);       /* v = dy^2+1 */
1239          $u = self::fe_sq($h->Y);
1240          /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
1241          $v = self::fe_mul($u, $d);
1242          $u = self::fe_sub($u, $h->Z); /* u =  y^2 - 1 */
1243          $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
1244  
1245          # fe_sq(v3,v);
1246          # fe_mul(v3,v3,v);        /* v3 = v^3 */
1247          # fe_sq(h->X,v3);
1248          # fe_mul(h->X,h->X,v);
1249          # fe_mul(h->X,h->X,u);    /* x = uv^7 */
1250          $v3 = self::fe_sq($v);
1251          $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
1252          $h->X = self::fe_sq($v3);
1253          $h->X = self::fe_mul($h->X, $v);
1254          $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
1255  
1256          # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
1257          # fe_mul(h->X,h->X,v3);
1258          # fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
1259          $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
1260          $h->X = self::fe_mul($h->X, $v3);
1261          $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
1262  
1263          # fe_sq(vxx,h->X);
1264          # fe_mul(vxx,vxx,v);
1265          # fe_sub(check,vxx,u);    /* vx^2-u */
1266          $vxx = self::fe_sq($h->X);
1267          $vxx = self::fe_mul($vxx, $v);
1268          $check = self::fe_sub($vxx, $u); /* vx^2 - u */
1269  
1270          # if (fe_isnonzero(check)) {
1271          #     fe_add(check,vxx,u);  /* vx^2+u */
1272          #     if (fe_isnonzero(check)) {
1273          #         return -1;
1274          #     }
1275          #     fe_mul(h->X,h->X,sqrtm1);
1276          # }
1277          if (self::fe_isnonzero($check)) {
1278              $check = self::fe_add($vxx, $u); /* vx^2 + u */
1279              if (self::fe_isnonzero($check)) {
1280                  throw new RangeException('Internal check failed.');
1281              }
1282              $h->X = self::fe_mul(
1283                  $h->X,
1284                  ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
1285              );
1286          }
1287  
1288          # if (fe_isnegative(h->X) == (s[31] >> 7)) {
1289          #     fe_neg(h->X,h->X);
1290          # }
1291          $i = self::chrToInt($s[31]);
1292          if (self::fe_isnegative($h->X) === ($i >> 7)) {
1293              $h->X = self::fe_neg($h->X);
1294          }
1295  
1296          # fe_mul(h->T,h->X,h->Y);
1297          $h->T = self::fe_mul($h->X, $h->Y);
1298          return $h;
1299      }
1300  
1301      /**
1302       * @internal You should not use this directly from another application
1303       *
1304       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
1305       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1306       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
1307       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
1308       */
1309      public static function ge_madd(
1310          ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
1311          ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
1312          ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
1313      ) {
1314          $r = clone $R;
1315          $r->X = self::fe_add($p->Y, $p->X);
1316          $r->Y = self::fe_sub($p->Y, $p->X);
1317          $r->Z = self::fe_mul($r->X, $q->yplusx);
1318          $r->Y = self::fe_mul($r->Y, $q->yminusx);
1319          $r->T = self::fe_mul($q->xy2d, $p->T);
1320          $t0 = self::fe_add(clone $p->Z, clone $p->Z);
1321          $r->X = self::fe_sub($r->Z, $r->Y);
1322          $r->Y = self::fe_add($r->Z, $r->Y);
1323          $r->Z = self::fe_add($t0, $r->T);
1324          $r->T = self::fe_sub($t0, $r->T);
1325  
1326          return $r;
1327      }
1328  
1329      /**
1330       * @internal You should not use this directly from another application
1331       *
1332       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
1333       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1334       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
1335       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
1336       */
1337      public static function ge_msub(
1338          ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
1339          ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
1340          ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
1341      ) {
1342          $r = clone $R;
1343  
1344          $r->X = self::fe_add($p->Y, $p->X);
1345          $r->Y = self::fe_sub($p->Y, $p->X);
1346          $r->Z = self::fe_mul($r->X, $q->yminusx);
1347          $r->Y = self::fe_mul($r->Y, $q->yplusx);
1348          $r->T = self::fe_mul($q->xy2d, $p->T);
1349          $t0 = self::fe_add($p->Z, $p->Z);
1350          $r->X = self::fe_sub($r->Z, $r->Y);
1351          $r->Y = self::fe_add($r->Z, $r->Y);
1352          $r->Z = self::fe_sub($t0, $r->T);
1353          $r->T = self::fe_add($t0, $r->T);
1354  
1355          return $r;
1356      }
1357  
1358      /**
1359       * @internal You should not use this directly from another application
1360       *
1361       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
1362       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
1363       */
1364      public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
1365      {
1366          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
1367          $r->X = self::fe_mul($p->X, $p->T);
1368          $r->Y = self::fe_mul($p->Y, $p->Z);
1369          $r->Z = self::fe_mul($p->Z, $p->T);
1370          return $r;
1371      }
1372  
1373      /**
1374       * @internal You should not use this directly from another application
1375       *
1376       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
1377       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
1378       */
1379      public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
1380      {
1381          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
1382          $r->X = self::fe_mul($p->X, $p->T);
1383          $r->Y = self::fe_mul($p->Y, $p->Z);
1384          $r->Z = self::fe_mul($p->Z, $p->T);
1385          $r->T = self::fe_mul($p->X, $p->Y);
1386          return $r;
1387      }
1388  
1389      /**
1390       * @internal You should not use this directly from another application
1391       *
1392       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
1393       */
1394      public static function ge_p2_0()
1395      {
1396          return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
1397              self::fe_0(),
1398              self::fe_1(),
1399              self::fe_1()
1400          );
1401      }
1402  
1403      /**
1404       * @internal You should not use this directly from another application
1405       *
1406       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
1407       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
1408       */
1409      public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p)
1410      {
1411          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
1412  
1413          $r->X = self::fe_sq($p->X);
1414          $r->Z = self::fe_sq($p->Y);
1415          $r->T = self::fe_sq2($p->Z);
1416          $r->Y = self::fe_add($p->X, $p->Y);
1417          $t0   = self::fe_sq($r->Y);
1418          $r->Y = self::fe_add($r->Z, $r->X);
1419          $r->Z = self::fe_sub($r->Z, $r->X);
1420          $r->X = self::fe_sub($t0, $r->Y);
1421          $r->T = self::fe_sub($r->T, $r->Z);
1422  
1423          return $r;
1424      }
1425  
1426      /**
1427       * @internal You should not use this directly from another application
1428       *
1429       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
1430       */
1431      public static function ge_p3_0()
1432      {
1433          return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
1434              self::fe_0(),
1435              self::fe_1(),
1436              self::fe_1(),
1437              self::fe_0()
1438          );
1439      }
1440  
1441      /**
1442       * @internal You should not use this directly from another application
1443       *
1444       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1445       * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
1446       */
1447      public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
1448      {
1449          static $d2 = null;
1450          if ($d2 === null) {
1451              $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
1452          }
1453          /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
1454          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
1455          $r->YplusX = self::fe_add($p->Y, $p->X);
1456          $r->YminusX = self::fe_sub($p->Y, $p->X);
1457          $r->Z = self::fe_copy($p->Z);
1458          $r->T2d = self::fe_mul($p->T, $d2);
1459          return $r;
1460      }
1461  
1462      /**
1463       * @internal You should not use this directly from another application
1464       *
1465       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1466       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
1467       */
1468      public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
1469      {
1470          return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
1471              self::fe_copy($p->X),
1472              self::fe_copy($p->Y),
1473              self::fe_copy($p->Z)
1474          );
1475      }
1476  
1477      /**
1478       * @internal You should not use this directly from another application
1479       *
1480       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
1481       * @return string
1482       * @throws SodiumException
1483       * @throws TypeError
1484       */
1485      public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
1486      {
1487          $recip = self::fe_invert($h->Z);
1488          $x = self::fe_mul($h->X, $recip);
1489          $y = self::fe_mul($h->Y, $recip);
1490          $s = self::fe_tobytes($y);
1491          $s[31] = self::intToChr(
1492              self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
1493          );
1494          return $s;
1495      }
1496  
1497      /**
1498       * @internal You should not use this directly from another application
1499       *
1500       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1501       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
1502       */
1503      public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
1504      {
1505          $q = self::ge_p3_to_p2($p);
1506          return self::ge_p2_dbl($q);
1507      }
1508  
1509      /**
1510       * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
1511       */
1512      public static function ge_precomp_0()
1513      {
1514          return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
1515              self::fe_1(),
1516              self::fe_1(),
1517              self::fe_0()
1518          );
1519      }
1520  
1521      /**
1522       * @internal You should not use this directly from another application
1523       *
1524       * @param int $b
1525       * @param int $c
1526       * @return int
1527       */
1528      public static function equal($b, $c)
1529      {
1530          return (int) ((($b ^ $c) - 1) >> 31) & 1;
1531      }
1532  
1533      /**
1534       * @internal You should not use this directly from another application
1535       *
1536       * @param int|string $char
1537       * @return int (1 = yes, 0 = no)
1538       * @throws SodiumException
1539       * @throws TypeError
1540       */
1541      public static function negative($char)
1542      {
1543          if (is_int($char)) {
1544              return ($char >> 63) & 1;
1545          }
1546          $x = self::chrToInt(self::substr($char, 0, 1));
1547          return (int) ($x >> 63);
1548      }
1549  
1550      /**
1551       * Conditional move
1552       *
1553       * @internal You should not use this directly from another application
1554       *
1555       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
1556       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
1557       * @param int $b
1558       * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
1559       */
1560      public static function cmov(
1561          ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
1562          ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
1563          $b
1564      ) {
1565          if (!is_int($b)) {
1566              throw new InvalidArgumentException('Expected an integer.');
1567          }
1568          return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
1569              self::fe_cmov($t->yplusx,  $u->yplusx,  $b),
1570              self::fe_cmov($t->yminusx, $u->yminusx, $b),
1571              self::fe_cmov($t->xy2d,    $u->xy2d,    $b)
1572          );
1573      }
1574  
1575      /**
1576       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t
1577       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u
1578       * @param int $b
1579       * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
1580       */
1581      public static function ge_cmov_cached(
1582          ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t,
1583          ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u,
1584          $b
1585      ) {
1586          $b &= 1;
1587          $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
1588          $ret->YplusX  = self::fe_cmov($t->YplusX,  $u->YplusX,  $b);
1589          $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b);
1590          $ret->Z       = self::fe_cmov($t->Z,       $u->Z,       $b);
1591          $ret->T2d     = self::fe_cmov($t->T2d,     $u->T2d,     $b);
1592          return $ret;
1593      }
1594  
1595      /**
1596       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached
1597       * @param int $b
1598       * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
1599       * @throws SodiumException
1600       */
1601      public static function ge_cmov8_cached(array $cached, $b)
1602      {
1603          // const unsigned char bnegative = negative(b);
1604          // const unsigned char babs      = b - (((-bnegative) & b) * ((signed char) 1 << 1));
1605          $bnegative = self::negative($b);
1606          $babs = $b - (((-$bnegative) & $b) << 1);
1607  
1608          // ge25519_cached_0(t);
1609          $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
1610              self::fe_1(),
1611              self::fe_1(),
1612              self::fe_1(),
1613              self::fe_0()
1614          );
1615  
1616          // ge25519_cmov_cached(t, &cached[0], equal(babs, 1));
1617          // ge25519_cmov_cached(t, &cached[1], equal(babs, 2));
1618          // ge25519_cmov_cached(t, &cached[2], equal(babs, 3));
1619          // ge25519_cmov_cached(t, &cached[3], equal(babs, 4));
1620          // ge25519_cmov_cached(t, &cached[4], equal(babs, 5));
1621          // ge25519_cmov_cached(t, &cached[5], equal(babs, 6));
1622          // ge25519_cmov_cached(t, &cached[6], equal(babs, 7));
1623          // ge25519_cmov_cached(t, &cached[7], equal(babs, 8));
1624          for ($x = 0; $x < 8; ++$x) {
1625              $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1));
1626          }
1627  
1628          // fe25519_copy(minust.YplusX, t->YminusX);
1629          // fe25519_copy(minust.YminusX, t->YplusX);
1630          // fe25519_copy(minust.Z, t->Z);
1631          // fe25519_neg(minust.T2d, t->T2d);
1632          $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
1633              self::fe_copy($t->YminusX),
1634              self::fe_copy($t->YplusX),
1635              self::fe_copy($t->Z),
1636              self::fe_neg($t->T2d)
1637          );
1638          return self::ge_cmov_cached($t, $minust, $bnegative);
1639      }
1640  
1641      /**
1642       * @internal You should not use this directly from another application
1643       *
1644       * @param int $pos
1645       * @param int $b
1646       * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
1647       * @throws SodiumException
1648       * @throws TypeError
1649       * @psalm-suppress MixedArgument
1650       * @psalm-suppress MixedArrayAccess
1651       * @psalm-suppress MixedArrayOffset
1652       */
1653      public static function ge_select($pos = 0, $b = 0)
1654      {
1655          static $base = null;
1656          if ($base === null) {
1657              $base = array();
1658              /** @var int $i */
1659              foreach (self::$base as $i => $bas) {
1660                  for ($j = 0; $j < 8; ++$j) {
1661                      $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
1662                          ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
1663                          ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
1664                          ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
1665                      );
1666                  }
1667              }
1668          }
1669          /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
1670          if (!is_int($pos)) {
1671              throw new InvalidArgumentException('Position must be an integer');
1672          }
1673          if ($pos < 0 || $pos > 31) {
1674              throw new RangeException('Position is out of range [0, 31]');
1675          }
1676  
1677          $bnegative = self::negative($b);
1678          $babs = $b - (((-$bnegative) & $b) << 1);
1679  
1680          $t = self::ge_precomp_0();
1681          for ($i = 0; $i < 8; ++$i) {
1682              $t = self::cmov(
1683                  $t,
1684                  $base[$pos][$i],
1685                  self::equal($babs, $i + 1)
1686              );
1687          }
1688          $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
1689              self::fe_copy($t->yminusx),
1690              self::fe_copy($t->yplusx),
1691              self::fe_neg($t->xy2d)
1692          );
1693          return self::cmov($t, $minusT, $bnegative);
1694      }
1695  
1696      /**
1697       * Subtract two group elements.
1698       *
1699       * r = p - q
1700       *
1701       * @internal You should not use this directly from another application
1702       *
1703       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1704       * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
1705       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
1706       */
1707      public static function ge_sub(
1708          ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
1709          ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
1710      ) {
1711          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
1712  
1713          $r->X = self::fe_add($p->Y, $p->X);
1714          $r->Y = self::fe_sub($p->Y, $p->X);
1715          $r->Z = self::fe_mul($r->X, $q->YminusX);
1716          $r->Y = self::fe_mul($r->Y, $q->YplusX);
1717          $r->T = self::fe_mul($q->T2d, $p->T);
1718          $r->X = self::fe_mul($p->Z, $q->Z);
1719          $t0 = self::fe_add($r->X, $r->X);
1720          $r->X = self::fe_sub($r->Z, $r->Y);
1721          $r->Y = self::fe_add($r->Z, $r->Y);
1722          $r->Z = self::fe_sub($t0, $r->T);
1723          $r->T = self::fe_add($t0, $r->T);
1724  
1725          return $r;
1726      }
1727  
1728      /**
1729       * Convert a group element to a byte string.
1730       *
1731       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
1732       * @return string
1733       * @throws SodiumException
1734       * @throws TypeError
1735       */
1736      public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
1737      {
1738          $recip = self::fe_invert($h->Z);
1739          $x = self::fe_mul($h->X, $recip);
1740          $y = self::fe_mul($h->Y, $recip);
1741          $s = self::fe_tobytes($y);
1742          $s[31] = self::intToChr(
1743              self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
1744          );
1745          return $s;
1746      }
1747  
1748      /**
1749       * @internal You should not use this directly from another application
1750       *
1751       * @param string $a
1752       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
1753       * @param string $b
1754       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
1755       * @throws SodiumException
1756       * @throws TypeError
1757       * @psalm-suppress MixedArgument
1758       * @psalm-suppress MixedArrayAccess
1759       */
1760      public static function ge_double_scalarmult_vartime(
1761          $a,
1762          ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
1763          $b
1764      ) {
1765          /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
1766          $Ai = array();
1767  
1768          /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
1769          static $Bi = array();
1770          if (!$Bi) {
1771              for ($i = 0; $i < 8; ++$i) {
1772                  $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
1773                      ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
1774                      ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
1775                      ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
1776                  );
1777              }
1778          }
1779          for ($i = 0; $i < 8; ++$i) {
1780              $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
1781                  self::fe_0(),
1782                  self::fe_0(),
1783                  self::fe_0(),
1784                  self::fe_0()
1785              );
1786          }
1787  
1788          # slide(aslide,a);
1789          # slide(bslide,b);
1790          /** @var array<int, int> $aslide */
1791          $aslide = self::slide($a);
1792          /** @var array<int, int> $bslide */
1793          $bslide = self::slide($b);
1794  
1795          # ge_p3_to_cached(&Ai[0],A);
1796          # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
1797          $Ai[0] = self::ge_p3_to_cached($A);
1798          $t = self::ge_p3_dbl($A);
1799          $A2 = self::ge_p1p1_to_p3($t);
1800  
1801          # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
1802          # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
1803          # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
1804          # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
1805          # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
1806          # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
1807          # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
1808          for ($i = 0; $i < 7; ++$i) {
1809              $t = self::ge_add($A2, $Ai[$i]);
1810              $u = self::ge_p1p1_to_p3($t);
1811              $Ai[$i + 1] = self::ge_p3_to_cached($u);
1812          }
1813  
1814          # ge_p2_0(r);
1815          $r = self::ge_p2_0();
1816  
1817          # for (i = 255;i >= 0;--i) {
1818          #     if (aslide[i] || bslide[i]) break;
1819          # }
1820          $i = 255;
1821          for (; $i >= 0; --$i) {
1822              if ($aslide[$i] || $bslide[$i]) {
1823                  break;
1824              }
1825          }
1826  
1827          # for (;i >= 0;--i) {
1828          for (; $i >= 0; --$i) {
1829              # ge_p2_dbl(&t,r);
1830              $t = self::ge_p2_dbl($r);
1831  
1832              # if (aslide[i] > 0) {
1833              if ($aslide[$i] > 0) {
1834                  # ge_p1p1_to_p3(&u,&t);
1835                  # ge_add(&t,&u,&Ai[aslide[i]/2]);
1836                  $u = self::ge_p1p1_to_p3($t);
1837                  $t = self::ge_add(
1838                      $u,
1839                      $Ai[(int) floor($aslide[$i] / 2)]
1840                  );
1841              # } else if (aslide[i] < 0) {
1842              } elseif ($aslide[$i] < 0) {
1843                  # ge_p1p1_to_p3(&u,&t);
1844                  # ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
1845                  $u = self::ge_p1p1_to_p3($t);
1846                  $t = self::ge_sub(
1847                      $u,
1848                      $Ai[(int) floor(-$aslide[$i] / 2)]
1849                  );
1850              }
1851  
1852              # if (bslide[i] > 0) {
1853              if ($bslide[$i] > 0) {
1854                  /** @var int $index */
1855                  $index = (int) floor($bslide[$i] / 2);
1856                  # ge_p1p1_to_p3(&u,&t);
1857                  # ge_madd(&t,&u,&Bi[bslide[i]/2]);
1858                  $u = self::ge_p1p1_to_p3($t);
1859                  $t = self::ge_madd($t, $u, $Bi[$index]);
1860              # } else if (bslide[i] < 0) {
1861              } elseif ($bslide[$i] < 0) {
1862                  /** @var int $index */
1863                  $index = (int) floor(-$bslide[$i] / 2);
1864                  # ge_p1p1_to_p3(&u,&t);
1865                  # ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
1866                  $u = self::ge_p1p1_to_p3($t);
1867                  $t = self::ge_msub($t, $u, $Bi[$index]);
1868              }
1869              # ge_p1p1_to_p2(r,&t);
1870              $r = self::ge_p1p1_to_p2($t);
1871          }
1872          return $r;
1873      }
1874  
1875      /**
1876       * @internal You should not use this directly from another application
1877       *
1878       * @param string $a
1879       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
1880       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
1881       * @throws SodiumException
1882       * @throws TypeError
1883       * @psalm-suppress MixedAssignment
1884       * @psalm-suppress MixedOperand
1885       */
1886      public static function ge_scalarmult($a, $p)
1887      {
1888          $e = array_fill(0, 64, 0);
1889  
1890          /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */
1891          $pi = array();
1892  
1893          //        ge25519_p3_to_cached(&pi[1 - 1], p);   /* p */
1894          $pi[0] = self::ge_p3_to_cached($p);
1895  
1896          //        ge25519_p3_dbl(&t2, p);
1897          //        ge25519_p1p1_to_p3(&p2, &t2);
1898          //        ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */
1899          $t2 = self::ge_p3_dbl($p);
1900          $p2 = self::ge_p1p1_to_p3($t2);
1901          $pi[1] = self::ge_p3_to_cached($p2);
1902  
1903          //        ge25519_add_cached(&t3, p, &pi[2 - 1]);
1904          //        ge25519_p1p1_to_p3(&p3, &t3);
1905          //        ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */
1906          $t3 = self::ge_add($p, $pi[1]);
1907          $p3 = self::ge_p1p1_to_p3($t3);
1908          $pi[2] = self::ge_p3_to_cached($p3);
1909  
1910          //        ge25519_p3_dbl(&t4, &p2);
1911          //        ge25519_p1p1_to_p3(&p4, &t4);
1912          //        ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */
1913          $t4 = self::ge_p3_dbl($p2);
1914          $p4 = self::ge_p1p1_to_p3($t4);
1915          $pi[3] = self::ge_p3_to_cached($p4);
1916  
1917          //        ge25519_add_cached(&t5, p, &pi[4 - 1]);
1918          //        ge25519_p1p1_to_p3(&p5, &t5);
1919          //        ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */
1920          $t5 = self::ge_add($p, $pi[3]);
1921          $p5 = self::ge_p1p1_to_p3($t5);
1922          $pi[4] = self::ge_p3_to_cached($p5);
1923  
1924          //        ge25519_p3_dbl(&t6, &p3);
1925          //        ge25519_p1p1_to_p3(&p6, &t6);
1926          //        ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */
1927          $t6 = self::ge_p3_dbl($p3);
1928          $p6 = self::ge_p1p1_to_p3($t6);
1929          $pi[5] = self::ge_p3_to_cached($p6);
1930  
1931          //        ge25519_add_cached(&t7, p, &pi[6 - 1]);
1932          //        ge25519_p1p1_to_p3(&p7, &t7);
1933          //        ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */
1934          $t7 = self::ge_add($p, $pi[5]);
1935          $p7 = self::ge_p1p1_to_p3($t7);
1936          $pi[6] = self::ge_p3_to_cached($p7);
1937  
1938          //        ge25519_p3_dbl(&t8, &p4);
1939          //        ge25519_p1p1_to_p3(&p8, &t8);
1940          //        ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */
1941          $t8 = self::ge_p3_dbl($p4);
1942          $p8 = self::ge_p1p1_to_p3($t8);
1943          $pi[7] = self::ge_p3_to_cached($p8);
1944  
1945  
1946          //        for (i = 0; i < 32; ++i) {
1947          //            e[2 * i + 0] = (a[i] >> 0) & 15;
1948          //            e[2 * i + 1] = (a[i] >> 4) & 15;
1949          //        }
1950          for ($i = 0; $i < 32; ++$i) {
1951              $e[($i << 1)    ] =  self::chrToInt($a[$i]) & 15;
1952              $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15;
1953          }
1954          //        /* each e[i] is between 0 and 15 */
1955          //        /* e[63] is between 0 and 7 */
1956  
1957          //        carry = 0;
1958          //        for (i = 0; i < 63; ++i) {
1959          //            e[i] += carry;
1960          //            carry = e[i] + 8;
1961          //            carry >>= 4;
1962          //            e[i] -= carry * ((signed char) 1 << 4);
1963          //        }
1964          $carry = 0;
1965          for ($i = 0; $i < 63; ++$i) {
1966              $e[$i] += $carry;
1967              $carry = $e[$i] + 8;
1968              $carry >>= 4;
1969              $e[$i] -= $carry << 4;
1970          }
1971          //        e[63] += carry;
1972          //        /* each e[i] is between -8 and 8 */
1973          $e[63] += $carry;
1974  
1975          //        ge25519_p3_0(h);
1976          $h = self::ge_p3_0();
1977  
1978          //        for (i = 63; i != 0; i--) {
1979          for ($i = 63; $i != 0; --$i) {
1980              // ge25519_cmov8_cached(&t, pi, e[i]);
1981              $t = self::ge_cmov8_cached($pi, $e[$i]);
1982              // ge25519_add_cached(&r, h, &t);
1983              $r = self::ge_add($h, $t);
1984  
1985              // ge25519_p1p1_to_p2(&s, &r);
1986              // ge25519_p2_dbl(&r, &s);
1987              // ge25519_p1p1_to_p2(&s, &r);
1988              // ge25519_p2_dbl(&r, &s);
1989              // ge25519_p1p1_to_p2(&s, &r);
1990              // ge25519_p2_dbl(&r, &s);
1991              // ge25519_p1p1_to_p2(&s, &r);
1992              // ge25519_p2_dbl(&r, &s);
1993              $s = self::ge_p1p1_to_p2($r);
1994              $r = self::ge_p2_dbl($s);
1995              $s = self::ge_p1p1_to_p2($r);
1996              $r = self::ge_p2_dbl($s);
1997              $s = self::ge_p1p1_to_p2($r);
1998              $r = self::ge_p2_dbl($s);
1999              $s = self::ge_p1p1_to_p2($r);
2000              $r = self::ge_p2_dbl($s);
2001  
2002              // ge25519_p1p1_to_p3(h, &r);  /* *16 */
2003              $h = self::ge_p1p1_to_p3($r); /* *16 */
2004          }
2005  
2006          //        ge25519_cmov8_cached(&t, pi, e[i]);
2007          //        ge25519_add_cached(&r, h, &t);
2008          //        ge25519_p1p1_to_p3(h, &r);
2009          $t = self::ge_cmov8_cached($pi, $e[0]);
2010          $r = self::ge_add($h, $t);
2011          return self::ge_p1p1_to_p3($r);
2012      }
2013  
2014      /**
2015       * @internal You should not use this directly from another application
2016       *
2017       * @param string $a
2018       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
2019       * @throws SodiumException
2020       * @throws TypeError
2021       * @psalm-suppress MixedAssignment
2022       * @psalm-suppress MixedOperand
2023       */
2024      public static function ge_scalarmult_base($a)
2025      {
2026          /** @var array<int, int> $e */
2027          $e = array();
2028          $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
2029  
2030          for ($i = 0; $i < 32; ++$i) {
2031              $dbl = (int) $i << 1;
2032              $e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
2033              $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
2034          }
2035  
2036          $carry = 0;
2037          for ($i = 0; $i < 63; ++$i) {
2038              $e[$i] += $carry;
2039              $carry = $e[$i] + 8;
2040              $carry >>= 4;
2041              $e[$i] -= $carry << 4;
2042          }
2043          $e[63] += (int) $carry;
2044  
2045          $h = self::ge_p3_0();
2046  
2047          for ($i = 1; $i < 64; $i += 2) {
2048              $t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
2049              $r = self::ge_madd($r, $h, $t);
2050              $h = self::ge_p1p1_to_p3($r);
2051          }
2052  
2053          $r = self::ge_p3_dbl($h);
2054  
2055          $s = self::ge_p1p1_to_p2($r);
2056          $r = self::ge_p2_dbl($s);
2057          $s = self::ge_p1p1_to_p2($r);
2058          $r = self::ge_p2_dbl($s);
2059          $s = self::ge_p1p1_to_p2($r);
2060          $r = self::ge_p2_dbl($s);
2061  
2062          $h = self::ge_p1p1_to_p3($r);
2063  
2064          for ($i = 0; $i < 64; $i += 2) {
2065              $t = self::ge_select($i >> 1, (int) $e[$i]);
2066              $r = self::ge_madd($r, $h, $t);
2067              $h = self::ge_p1p1_to_p3($r);
2068          }
2069          return $h;
2070      }
2071  
2072      /**
2073       * Calculates (ab + c) mod l
2074       * where l = 2^252 + 27742317777372353535851937790883648493
2075       *
2076       * @internal You should not use this directly from another application
2077       *
2078       * @param string $a
2079       * @param string $b
2080       * @param string $c
2081       * @return string
2082       * @throws TypeError
2083       */
2084      public static function sc_muladd($a, $b, $c)
2085      {
2086          $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
2087          $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
2088          $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
2089          $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
2090          $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
2091          $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
2092          $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
2093          $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
2094          $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
2095          $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
2096          $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
2097          $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
2098  
2099          $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
2100          $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
2101          $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
2102          $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
2103          $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
2104          $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
2105          $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
2106          $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
2107          $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
2108          $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
2109          $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
2110          $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
2111  
2112          $c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
2113          $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5);
2114          $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2);
2115          $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7);
2116          $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4);
2117          $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1);
2118          $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6);
2119          $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3);
2120          $c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
2121          $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5);
2122          $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2);
2123          $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);
2124  
2125          /* Can't really avoid the pyramid here: */
2126          $s0 = $c0 + self::mul($a0, $b0, 24);
2127          $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
2128          $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24);
2129          $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
2130          $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
2131                 self::mul($a4, $b0, 24);
2132          $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
2133                 self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
2134          $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
2135                 self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24);
2136          $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
2137                 self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
2138          $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
2139                 self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
2140                 self::mul($a8, $b0, 24);
2141          $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
2142                 self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
2143                 self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
2144          $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
2145                 self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
2146                 self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24);
2147          $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
2148                 self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
2149                 self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
2150          $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
2151                 self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
2152                 self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24);
2153          $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
2154                 self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
2155                 self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
2156          $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
2157                 self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
2158                 self::mul($a11, $b3, 24);
2159          $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
2160                 self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
2161          $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
2162                 self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24);
2163          $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
2164                 self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
2165          $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
2166                 self::mul($a11, $b7, 24);
2167          $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
2168          $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24);
2169          $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
2170          $s22 = self::mul($a11, $b11, 24);
2171          $s23 = 0;
2172  
2173          $carry0 = ($s0 + (1 << 20)) >> 21;
2174          $s1 += $carry0;
2175          $s0 -= $carry0 << 21;
2176          $carry2 = ($s2 + (1 << 20)) >> 21;
2177          $s3 += $carry2;
2178          $s2 -= $carry2 << 21;
2179          $carry4 = ($s4 + (1 << 20)) >> 21;
2180          $s5 += $carry4;
2181          $s4 -= $carry4 << 21;
2182          $carry6 = ($s6 + (1 << 20)) >> 21;
2183          $s7 += $carry6;
2184          $s6 -= $carry6 << 21;
2185          $carry8 = ($s8 + (1 << 20)) >> 21;
2186          $s9 += $carry8;
2187          $s8 -= $carry8 << 21;
2188          $carry10 = ($s10 + (1 << 20)) >> 21;
2189          $s11 += $carry10;
2190          $s10 -= $carry10 << 21;
2191          $carry12 = ($s12 + (1 << 20)) >> 21;
2192          $s13 += $carry12;
2193          $s12 -= $carry12 << 21;
2194          $carry14 = ($s14 + (1 << 20)) >> 21;
2195          $s15 += $carry14;
2196          $s14 -= $carry14 << 21;
2197          $carry16 = ($s16 + (1 << 20)) >> 21;
2198          $s17 += $carry16;
2199          $s16 -= $carry16 << 21;
2200          $carry18 = ($s18 + (1 << 20)) >> 21;
2201          $s19 += $carry18;
2202          $s18 -= $carry18 << 21;
2203          $carry20 = ($s20 + (1 << 20)) >> 21;
2204          $s21 += $carry20;
2205          $s20 -= $carry20 << 21;
2206          $carry22 = ($s22 + (1 << 20)) >> 21;
2207          $s23 += $carry22;
2208          $s22 -= $carry22 << 21;
2209  
2210          $carry1 = ($s1 + (1 << 20)) >> 21;
2211          $s2 += $carry1;
2212          $s1 -= $carry1 << 21;
2213          $carry3 = ($s3 + (1 << 20)) >> 21;
2214          $s4 += $carry3;
2215          $s3 -= $carry3 << 21;
2216          $carry5 = ($s5 + (1 << 20)) >> 21;
2217          $s6 += $carry5;
2218          $s5 -= $carry5 << 21;
2219          $carry7 = ($s7 + (1 << 20)) >> 21;
2220          $s8 += $carry7;
2221          $s7 -= $carry7 << 21;
2222          $carry9 = ($s9 + (1 << 20)) >> 21;
2223          $s10 += $carry9;
2224          $s9 -= $carry9 << 21;
2225          $carry11 = ($s11 + (1 << 20)) >> 21;
2226          $s12 += $carry11;
2227          $s11 -= $carry11 << 21;
2228          $carry13 = ($s13 + (1 << 20)) >> 21;
2229          $s14 += $carry13;
2230          $s13 -= $carry13 << 21;
2231          $carry15 = ($s15 + (1 << 20)) >> 21;
2232          $s16 += $carry15;
2233          $s15 -= $carry15 << 21;
2234          $carry17 = ($s17 + (1 << 20)) >> 21;
2235          $s18 += $carry17;
2236          $s17 -= $carry17 << 21;
2237          $carry19 = ($s19 + (1 << 20)) >> 21;
2238          $s20 += $carry19;
2239          $s19 -= $carry19 << 21;
2240          $carry21 = ($s21 + (1 << 20)) >> 21;
2241          $s22 += $carry21;
2242          $s21 -= $carry21 << 21;
2243  
2244          $s11 += self::mul($s23, 666643, 20);
2245          $s12 += self::mul($s23, 470296, 19);
2246          $s13 += self::mul($s23, 654183, 20);
2247          $s14 -= self::mul($s23, 997805, 20);
2248          $s15 += self::mul($s23, 136657, 18);
2249          $s16 -= self::mul($s23, 683901, 20);
2250  
2251          $s10 += self::mul($s22, 666643, 20);
2252          $s11 += self::mul($s22, 470296, 19);
2253          $s12 += self::mul($s22, 654183, 20);
2254          $s13 -= self::mul($s22, 997805, 20);
2255          $s14 += self::mul($s22, 136657, 18);
2256          $s15 -= self::mul($s22, 683901, 20);
2257  
2258          $s9  += self::mul($s21,  666643, 20);
2259          $s10 += self::mul($s21,  470296, 19);
2260          $s11 += self::mul($s21,  654183, 20);
2261          $s12 -= self::mul($s21,  997805, 20);
2262          $s13 += self::mul($s21,  136657, 18);
2263          $s14 -= self::mul($s21,  683901, 20);
2264  
2265          $s8  += self::mul($s20,  666643, 20);
2266          $s9  += self::mul($s20,  470296, 19);
2267          $s10 += self::mul($s20,  654183, 20);
2268          $s11 -= self::mul($s20,  997805, 20);
2269          $s12 += self::mul($s20,  136657, 18);
2270          $s13 -= self::mul($s20,  683901, 20);
2271  
2272          $s7  += self::mul($s19,  666643, 20);
2273          $s8  += self::mul($s19,  470296, 19);
2274          $s9  += self::mul($s19,  654183, 20);
2275          $s10 -= self::mul($s19,  997805, 20);
2276          $s11 += self::mul($s19,  136657, 18);
2277          $s12 -= self::mul($s19,  683901, 20);
2278  
2279          $s6  += self::mul($s18,  666643, 20);
2280          $s7  += self::mul($s18,  470296, 19);
2281          $s8  += self::mul($s18,  654183, 20);
2282          $s9  -= self::mul($s18,  997805, 20);
2283          $s10 += self::mul($s18,  136657, 18);
2284          $s11 -= self::mul($s18,  683901, 20);
2285  
2286          $carry6 = ($s6 + (1 << 20)) >> 21;
2287          $s7 += $carry6;
2288          $s6 -= $carry6 << 21;
2289          $carry8 = ($s8 + (1 << 20)) >> 21;
2290          $s9 += $carry8;
2291          $s8 -= $carry8 << 21;
2292          $carry10 = ($s10 + (1 << 20)) >> 21;
2293          $s11 += $carry10;
2294          $s10 -= $carry10 << 21;
2295          $carry12 = ($s12 + (1 << 20)) >> 21;
2296          $s13 += $carry12;
2297          $s12 -= $carry12 << 21;
2298          $carry14 = ($s14 + (1 << 20)) >> 21;
2299          $s15 += $carry14;
2300          $s14 -= $carry14 << 21;
2301          $carry16 = ($s16 + (1 << 20)) >> 21;
2302          $s17 += $carry16;
2303          $s16 -= $carry16 << 21;
2304  
2305          $carry7 = ($s7 + (1 << 20)) >> 21;
2306          $s8 += $carry7;
2307          $s7 -= $carry7 << 21;
2308          $carry9 = ($s9 + (1 << 20)) >> 21;
2309          $s10 += $carry9;
2310          $s9 -= $carry9 << 21;
2311          $carry11 = ($s11 + (1 << 20)) >> 21;
2312          $s12 += $carry11;
2313          $s11 -= $carry11 << 21;
2314          $carry13 = ($s13 + (1 << 20)) >> 21;
2315          $s14 += $carry13;
2316          $s13 -= $carry13 << 21;
2317          $carry15 = ($s15 + (1 << 20)) >> 21;
2318          $s16 += $carry15;
2319          $s15 -= $carry15 << 21;
2320  
2321          $s5  += self::mul($s17,  666643, 20);
2322          $s6  += self::mul($s17,  470296, 19);
2323          $s7  += self::mul($s17,  654183, 20);
2324          $s8  -= self::mul($s17,  997805, 20);
2325          $s9  += self::mul($s17,  136657, 18);
2326          $s10 -= self::mul($s17,  683901, 20);
2327  
2328          $s4 += self::mul($s16,  666643, 20);
2329          $s5 += self::mul($s16,  470296, 19);
2330          $s6 += self::mul($s16,  654183, 20);
2331          $s7 -= self::mul($s16,  997805, 20);
2332          $s8 += self::mul($s16,  136657, 18);
2333          $s9 -= self::mul($s16,  683901, 20);
2334  
2335          $s3 += self::mul($s15,  666643, 20);
2336          $s4 += self::mul($s15,  470296, 19);
2337          $s5 += self::mul($s15,  654183, 20);
2338          $s6 -= self::mul($s15,  997805, 20);
2339          $s7 += self::mul($s15,  136657, 18);
2340          $s8 -= self::mul($s15,  683901, 20);
2341  
2342          $s2 += self::mul($s14,  666643, 20);
2343          $s3 += self::mul($s14,  470296, 19);
2344          $s4 += self::mul($s14,  654183, 20);
2345          $s5 -= self::mul($s14,  997805, 20);
2346          $s6 += self::mul($s14,  136657, 18);
2347          $s7 -= self::mul($s14,  683901, 20);
2348  
2349          $s1 += self::mul($s13,  666643, 20);
2350          $s2 += self::mul($s13,  470296, 19);
2351          $s3 += self::mul($s13,  654183, 20);
2352          $s4 -= self::mul($s13,  997805, 20);
2353          $s5 += self::mul($s13,  136657, 18);
2354          $s6 -= self::mul($s13,  683901, 20);
2355  
2356          $s0 += self::mul($s12,  666643, 20);
2357          $s1 += self::mul($s12,  470296, 19);
2358          $s2 += self::mul($s12,  654183, 20);
2359          $s3 -= self::mul($s12,  997805, 20);
2360          $s4 += self::mul($s12,  136657, 18);
2361          $s5 -= self::mul($s12,  683901, 20);
2362          $s12 = 0;
2363  
2364          $carry0 = ($s0 + (1 << 20)) >> 21;
2365          $s1 += $carry0;
2366          $s0 -= $carry0 << 21;
2367          $carry2 = ($s2 + (1 << 20)) >> 21;
2368          $s3 += $carry2;
2369          $s2 -= $carry2 << 21;
2370          $carry4 = ($s4 + (1 << 20)) >> 21;
2371          $s5 += $carry4;
2372          $s4 -= $carry4 << 21;
2373          $carry6 = ($s6 + (1 << 20)) >> 21;
2374          $s7 += $carry6;
2375          $s6 -= $carry6 << 21;
2376          $carry8 = ($s8 + (1 << 20)) >> 21;
2377          $s9 += $carry8;
2378          $s8 -= $carry8 << 21;
2379          $carry10 = ($s10 + (1 << 20)) >> 21;
2380          $s11 += $carry10;
2381          $s10 -= $carry10 << 21;
2382  
2383          $carry1 = ($s1 + (1 << 20)) >> 21;
2384          $s2 += $carry1;
2385          $s1 -= $carry1 << 21;
2386          $carry3 = ($s3 + (1 << 20)) >> 21;
2387          $s4 += $carry3;
2388          $s3 -= $carry3 << 21;
2389          $carry5 = ($s5 + (1 << 20)) >> 21;
2390          $s6 += $carry5;
2391          $s5 -= $carry5 << 21;
2392          $carry7 = ($s7 + (1 << 20)) >> 21;
2393          $s8 += $carry7;
2394          $s7 -= $carry7 << 21;
2395          $carry9 = ($s9 + (1 << 20)) >> 21;
2396          $s10 += $carry9;
2397          $s9 -= $carry9 << 21;
2398          $carry11 = ($s11 + (1 << 20)) >> 21;
2399          $s12 += $carry11;
2400          $s11 -= $carry11 << 21;
2401  
2402          $s0 += self::mul($s12,  666643, 20);
2403          $s1 += self::mul($s12,  470296, 19);
2404          $s2 += self::mul($s12,  654183, 20);
2405          $s3 -= self::mul($s12,  997805, 20);
2406          $s4 += self::mul($s12,  136657, 18);
2407          $s5 -= self::mul($s12,  683901, 20);
2408          $s12 = 0;
2409  
2410          $carry0 = $s0 >> 21;
2411          $s1 += $carry0;
2412          $s0 -= $carry0 << 21;
2413          $carry1 = $s1 >> 21;
2414          $s2 += $carry1;
2415          $s1 -= $carry1 << 21;
2416          $carry2 = $s2 >> 21;
2417          $s3 += $carry2;
2418          $s2 -= $carry2 << 21;
2419          $carry3 = $s3 >> 21;
2420          $s4 += $carry3;
2421          $s3 -= $carry3 << 21;
2422          $carry4 = $s4 >> 21;
2423          $s5 += $carry4;
2424          $s4 -= $carry4 << 21;
2425          $carry5 = $s5 >> 21;
2426          $s6 += $carry5;
2427          $s5 -= $carry5 << 21;
2428          $carry6 = $s6 >> 21;
2429          $s7 += $carry6;
2430          $s6 -= $carry6 << 21;
2431          $carry7 = $s7 >> 21;
2432          $s8 += $carry7;
2433          $s7 -= $carry7 << 21;
2434          $carry8 = $s8 >> 21;
2435          $s9 += $carry8;
2436          $s8 -= $carry8 << 21;
2437          $carry9 = $s9 >> 21;
2438          $s10 += $carry9;
2439          $s9 -= $carry9 << 21;
2440          $carry10 = $s10 >> 21;
2441          $s11 += $carry10;
2442          $s10 -= $carry10 << 21;
2443          $carry11 = $s11 >> 21;
2444          $s12 += $carry11;
2445          $s11 -= $carry11 << 21;
2446  
2447          $s0 += self::mul($s12,  666643, 20);
2448          $s1 += self::mul($s12,  470296, 19);
2449          $s2 += self::mul($s12,  654183, 20);
2450          $s3 -= self::mul($s12,  997805, 20);
2451          $s4 += self::mul($s12,  136657, 18);
2452          $s5 -= self::mul($s12,  683901, 20);
2453  
2454          $carry0 = $s0 >> 21;
2455          $s1 += $carry0;
2456          $s0 -= $carry0 << 21;
2457          $carry1 = $s1 >> 21;
2458          $s2 += $carry1;
2459          $s1 -= $carry1 << 21;
2460          $carry2 = $s2 >> 21;
2461          $s3 += $carry2;
2462          $s2 -= $carry2 << 21;
2463          $carry3 = $s3 >> 21;
2464          $s4 += $carry3;
2465          $s3 -= $carry3 << 21;
2466          $carry4 = $s4 >> 21;
2467          $s5 += $carry4;
2468          $s4 -= $carry4 << 21;
2469          $carry5 = $s5 >> 21;
2470          $s6 += $carry5;
2471          $s5 -= $carry5 << 21;
2472          $carry6 = $s6 >> 21;
2473          $s7 += $carry6;
2474          $s6 -= $carry6 << 21;
2475          $carry7 = $s7 >> 21;
2476          $s8 += $carry7;
2477          $s7 -= $carry7 << 21;
2478          $carry8 = $s8 >> 21;
2479          $s9 += $carry8;
2480          $s8 -= $carry8 << 21;
2481          $carry9 = $s9 >> 21;
2482          $s10 += $carry9;
2483          $s9 -= $carry9 << 21;
2484          $carry10 = $s10 >> 21;
2485          $s11 += $carry10;
2486          $s10 -= $carry10 << 21;
2487  
2488          /**
2489           * @var array<int, int>
2490           */
2491          $arr = array(
2492              (int) (0xff & ($s0 >> 0)),
2493              (int) (0xff & ($s0 >> 8)),
2494              (int) (0xff & (($s0 >> 16) | $s1 << 5)),
2495              (int) (0xff & ($s1 >> 3)),
2496              (int) (0xff & ($s1 >> 11)),
2497              (int) (0xff & (($s1 >> 19) | $s2 << 2)),
2498              (int) (0xff & ($s2 >> 6)),
2499              (int) (0xff & (($s2 >> 14) | $s3 << 7)),
2500              (int) (0xff & ($s3 >> 1)),
2501              (int) (0xff & ($s3 >> 9)),
2502              (int) (0xff & (($s3 >> 17) | $s4 << 4)),
2503              (int) (0xff & ($s4 >> 4)),
2504              (int) (0xff & ($s4 >> 12)),
2505              (int) (0xff & (($s4 >> 20) | $s5 << 1)),
2506              (int) (0xff & ($s5 >> 7)),
2507              (int) (0xff & (($s5 >> 15) | $s6 << 6)),
2508              (int) (0xff & ($s6 >> 2)),
2509              (int) (0xff & ($s6 >> 10)),
2510              (int) (0xff & (($s6 >> 18) | $s7 << 3)),
2511              (int) (0xff & ($s7 >> 5)),
2512              (int) (0xff & ($s7 >> 13)),
2513              (int) (0xff & ($s8 >> 0)),
2514              (int) (0xff & ($s8 >> 8)),
2515              (int) (0xff & (($s8 >> 16) | $s9 << 5)),
2516              (int) (0xff & ($s9 >> 3)),
2517              (int) (0xff & ($s9 >> 11)),
2518              (int) (0xff & (($s9 >> 19) | $s10 << 2)),
2519              (int) (0xff & ($s10 >> 6)),
2520              (int) (0xff & (($s10 >> 14) | $s11 << 7)),
2521              (int) (0xff & ($s11 >> 1)),
2522              (int) (0xff & ($s11 >> 9)),
2523              0xff & ($s11 >> 17)
2524          );
2525          return self::intArrayToString($arr);
2526      }
2527  
2528      /**
2529       * @internal You should not use this directly from another application
2530       *
2531       * @param string $s
2532       * @return string
2533       * @throws TypeError
2534       */
2535      public static function sc_reduce($s)
2536      {
2537          $s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
2538          $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5);
2539          $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2);
2540          $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7);
2541          $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4);
2542          $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1);
2543          $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6);
2544          $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3);
2545          $s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
2546          $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5);
2547          $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2);
2548          $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7);
2549          $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4);
2550          $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1);
2551          $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6);
2552          $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3);
2553          $s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
2554          $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5);
2555          $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2);
2556          $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7);
2557          $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4);
2558          $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1);
2559          $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6);
2560          $s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3);
2561  
2562          $s11 += self::mul($s23,  666643, 20);
2563          $s12 += self::mul($s23,  470296, 19);
2564          $s13 += self::mul($s23,  654183, 20);
2565          $s14 -= self::mul($s23,  997805, 20);
2566          $s15 += self::mul($s23,  136657, 18);
2567          $s16 -= self::mul($s23,  683901, 20);
2568  
2569          $s10 += self::mul($s22,  666643, 20);
2570          $s11 += self::mul($s22,  470296, 19);
2571          $s12 += self::mul($s22,  654183, 20);
2572          $s13 -= self::mul($s22,  997805, 20);
2573          $s14 += self::mul($s22,  136657, 18);
2574          $s15 -= self::mul($s22,  683901, 20);
2575  
2576          $s9  += self::mul($s21,  666643, 20);
2577          $s10 += self::mul($s21,  470296, 19);
2578          $s11 += self::mul($s21,  654183, 20);
2579          $s12 -= self::mul($s21,  997805, 20);
2580          $s13 += self::mul($s21,  136657, 18);
2581          $s14 -= self::mul($s21,  683901, 20);
2582  
2583          $s8  += self::mul($s20,  666643, 20);
2584          $s9  += self::mul($s20,  470296, 19);
2585          $s10 += self::mul($s20,  654183, 20);
2586          $s11 -= self::mul($s20,  997805, 20);
2587          $s12 += self::mul($s20,  136657, 18);
2588          $s13 -= self::mul($s20,  683901, 20);
2589  
2590          $s7  += self::mul($s19,  666643, 20);
2591          $s8  += self::mul($s19,  470296, 19);
2592          $s9  += self::mul($s19,  654183, 20);
2593          $s10 -= self::mul($s19,  997805, 20);
2594          $s11 += self::mul($s19,  136657, 18);
2595          $s12 -= self::mul($s19,  683901, 20);
2596  
2597          $s6  += self::mul($s18,  666643, 20);
2598          $s7  += self::mul($s18,  470296, 19);
2599          $s8  += self::mul($s18,  654183, 20);
2600          $s9  -= self::mul($s18,  997805, 20);
2601          $s10 += self::mul($s18,  136657, 18);
2602          $s11 -= self::mul($s18,  683901, 20);
2603  
2604          $carry6 = ($s6 + (1 << 20)) >> 21;
2605          $s7 += $carry6;
2606          $s6 -= $carry6 << 21;
2607          $carry8 = ($s8 + (1 << 20)) >> 21;
2608          $s9 += $carry8;
2609          $s8 -= $carry8 << 21;
2610          $carry10 = ($s10 + (1 << 20)) >> 21;
2611          $s11 += $carry10;
2612          $s10 -= $carry10 << 21;
2613          $carry12 = ($s12 + (1 << 20)) >> 21;
2614          $s13 += $carry12;
2615          $s12 -= $carry12 << 21;
2616          $carry14 = ($s14 + (1 << 20)) >> 21;
2617          $s15 += $carry14;
2618          $s14 -= $carry14 << 21;
2619          $carry16 = ($s16 + (1 << 20)) >> 21;
2620          $s17 += $carry16;
2621          $s16 -= $carry16 << 21;
2622  
2623          $carry7 = ($s7 + (1 << 20)) >> 21;
2624          $s8 += $carry7;
2625          $s7 -= $carry7 << 21;
2626          $carry9 = ($s9 + (1 << 20)) >> 21;
2627          $s10 += $carry9;
2628          $s9 -= $carry9 << 21;
2629          $carry11 = ($s11 + (1 << 20)) >> 21;
2630          $s12 += $carry11;
2631          $s11 -= $carry11 << 21;
2632          $carry13 = ($s13 + (1 << 20)) >> 21;
2633          $s14 += $carry13;
2634          $s13 -= $carry13 << 21;
2635          $carry15 = ($s15 + (1 << 20)) >> 21;
2636          $s16 += $carry15;
2637          $s15 -= $carry15 << 21;
2638  
2639          $s5  += self::mul($s17,  666643, 20);
2640          $s6  += self::mul($s17,  470296, 19);
2641          $s7  += self::mul($s17,  654183, 20);
2642          $s8  -= self::mul($s17,  997805, 20);
2643          $s9  += self::mul($s17,  136657, 18);
2644          $s10 -= self::mul($s17,  683901, 20);
2645  
2646          $s4 += self::mul($s16,  666643, 20);
2647          $s5 += self::mul($s16,  470296, 19);
2648          $s6 += self::mul($s16,  654183, 20);
2649          $s7 -= self::mul($s16,  997805, 20);
2650          $s8 += self::mul($s16,  136657, 18);
2651          $s9 -= self::mul($s16,  683901, 20);
2652  
2653          $s3 += self::mul($s15,  666643, 20);
2654          $s4 += self::mul($s15,  470296, 19);
2655          $s5 += self::mul($s15,  654183, 20);
2656          $s6 -= self::mul($s15,  997805, 20);
2657          $s7 += self::mul($s15,  136657, 18);
2658          $s8 -= self::mul($s15,  683901, 20);
2659  
2660          $s2 += self::mul($s14,  666643, 20);
2661          $s3 += self::mul($s14,  470296, 19);
2662          $s4 += self::mul($s14,  654183, 20);
2663          $s5 -= self::mul($s14,  997805, 20);
2664          $s6 += self::mul($s14,  136657, 18);
2665          $s7 -= self::mul($s14,  683901, 20);
2666  
2667          $s1 += self::mul($s13,  666643, 20);
2668          $s2 += self::mul($s13,  470296, 19);
2669          $s3 += self::mul($s13,  654183, 20);
2670          $s4 -= self::mul($s13,  997805, 20);
2671          $s5 += self::mul($s13,  136657, 18);
2672          $s6 -= self::mul($s13,  683901, 20);
2673  
2674          $s0 += self::mul($s12,  666643, 20);
2675          $s1 += self::mul($s12,  470296, 19);
2676          $s2 += self::mul($s12,  654183, 20);
2677          $s3 -= self::mul($s12,  997805, 20);
2678          $s4 += self::mul($s12,  136657, 18);
2679          $s5 -= self::mul($s12,  683901, 20);
2680          $s12 = 0;
2681  
2682          $carry0 = ($s0 + (1 << 20)) >> 21;
2683          $s1 += $carry0;
2684          $s0 -= $carry0 << 21;
2685          $carry2 = ($s2 + (1 << 20)) >> 21;
2686          $s3 += $carry2;
2687          $s2 -= $carry2 << 21;
2688          $carry4 = ($s4 + (1 << 20)) >> 21;
2689          $s5 += $carry4;
2690          $s4 -= $carry4 << 21;
2691          $carry6 = ($s6 + (1 << 20)) >> 21;
2692          $s7 += $carry6;
2693          $s6 -= $carry6 << 21;
2694          $carry8 = ($s8 + (1 << 20)) >> 21;
2695          $s9 += $carry8;
2696          $s8 -= $carry8 << 21;
2697          $carry10 = ($s10 + (1 << 20)) >> 21;
2698          $s11 += $carry10;
2699          $s10 -= $carry10 << 21;
2700  
2701          $carry1 = ($s1 + (1 << 20)) >> 21;
2702          $s2 += $carry1;
2703          $s1 -= $carry1 << 21;
2704          $carry3 = ($s3 + (1 << 20)) >> 21;
2705          $s4 += $carry3;
2706          $s3 -= $carry3 << 21;
2707          $carry5 = ($s5 + (1 << 20)) >> 21;
2708          $s6 += $carry5;
2709          $s5 -= $carry5 << 21;
2710          $carry7 = ($s7 + (1 << 20)) >> 21;
2711          $s8 += $carry7;
2712          $s7 -= $carry7 << 21;
2713          $carry9 = ($s9 + (1 << 20)) >> 21;
2714          $s10 += $carry9;
2715          $s9 -= $carry9 << 21;
2716          $carry11 = ($s11 + (1 << 20)) >> 21;
2717          $s12 += $carry11;
2718          $s11 -= $carry11 << 21;
2719  
2720          $s0 += self::mul($s12,  666643, 20);
2721          $s1 += self::mul($s12,  470296, 19);
2722          $s2 += self::mul($s12,  654183, 20);
2723          $s3 -= self::mul($s12,  997805, 20);
2724          $s4 += self::mul($s12,  136657, 18);
2725          $s5 -= self::mul($s12,  683901, 20);
2726          $s12 = 0;
2727  
2728          $carry0 = $s0 >> 21;
2729          $s1 += $carry0;
2730          $s0 -= $carry0 << 21;
2731          $carry1 = $s1 >> 21;
2732          $s2 += $carry1;
2733          $s1 -= $carry1 << 21;
2734          $carry2 = $s2 >> 21;
2735          $s3 += $carry2;
2736          $s2 -= $carry2 << 21;
2737          $carry3 = $s3 >> 21;
2738          $s4 += $carry3;
2739          $s3 -= $carry3 << 21;
2740          $carry4 = $s4 >> 21;
2741          $s5 += $carry4;
2742          $s4 -= $carry4 << 21;
2743          $carry5 = $s5 >> 21;
2744          $s6 += $carry5;
2745          $s5 -= $carry5 << 21;
2746          $carry6 = $s6 >> 21;
2747          $s7 += $carry6;
2748          $s6 -= $carry6 << 21;
2749          $carry7 = $s7 >> 21;
2750          $s8 += $carry7;
2751          $s7 -= $carry7 << 21;
2752          $carry8 = $s8 >> 21;
2753          $s9 += $carry8;
2754          $s8 -= $carry8 << 21;
2755          $carry9 = $s9 >> 21;
2756          $s10 += $carry9;
2757          $s9 -= $carry9 << 21;
2758          $carry10 = $s10 >> 21;
2759          $s11 += $carry10;
2760          $s10 -= $carry10 << 21;
2761          $carry11 = $s11 >> 21;
2762          $s12 += $carry11;
2763          $s11 -= $carry11 << 21;
2764  
2765          $s0 += self::mul($s12,  666643, 20);
2766          $s1 += self::mul($s12,  470296, 19);
2767          $s2 += self::mul($s12,  654183, 20);
2768          $s3 -= self::mul($s12,  997805, 20);
2769          $s4 += self::mul($s12,  136657, 18);
2770          $s5 -= self::mul($s12,  683901, 20);
2771  
2772          $carry0 = $s0 >> 21;
2773          $s1 += $carry0;
2774          $s0 -= $carry0 << 21;
2775          $carry1 = $s1 >> 21;
2776          $s2 += $carry1;
2777          $s1 -= $carry1 << 21;
2778          $carry2 = $s2 >> 21;
2779          $s3 += $carry2;
2780          $s2 -= $carry2 << 21;
2781          $carry3 = $s3 >> 21;
2782          $s4 += $carry3;
2783          $s3 -= $carry3 << 21;
2784          $carry4 = $s4 >> 21;
2785          $s5 += $carry4;
2786          $s4 -= $carry4 << 21;
2787          $carry5 = $s5 >> 21;
2788          $s6 += $carry5;
2789          $s5 -= $carry5 << 21;
2790          $carry6 = $s6 >> 21;
2791          $s7 += $carry6;
2792          $s6 -= $carry6 << 21;
2793          $carry7 = $s7 >> 21;
2794          $s8 += $carry7;
2795          $s7 -= $carry7 << 21;
2796          $carry8 = $s8 >> 21;
2797          $s9 += $carry8;
2798          $s8 -= $carry8 << 21;
2799          $carry9 = $s9 >> 21;
2800          $s10 += $carry9;
2801          $s9 -= $carry9 << 21;
2802          $carry10 = $s10 >> 21;
2803          $s11 += $carry10;
2804          $s10 -= $carry10 << 21;
2805  
2806          /**
2807           * @var array<int, int>
2808           */
2809          $arr = array(
2810              (int) (0xff & ($s0 >> 0)),
2811              (int) (0xff & ($s0 >> 8)),
2812              (int) (0xff & (($s0 >> 16) | $s1 << 5)),
2813              (int) (0xff & ($s1 >> 3)),
2814              (int) (0xff & ($s1 >> 11)),
2815              (int) (0xff & (($s1 >> 19) | $s2 << 2)),
2816              (int) (0xff & ($s2 >> 6)),
2817              (int) (0xff & (($s2 >> 14) | $s3 << 7)),
2818              (int) (0xff & ($s3 >> 1)),
2819              (int) (0xff & ($s3 >> 9)),
2820              (int) (0xff & (($s3 >> 17) | $s4 << 4)),
2821              (int) (0xff & ($s4 >> 4)),
2822              (int) (0xff & ($s4 >> 12)),
2823              (int) (0xff & (($s4 >> 20) | $s5 << 1)),
2824              (int) (0xff & ($s5 >> 7)),
2825              (int) (0xff & (($s5 >> 15) | $s6 << 6)),
2826              (int) (0xff & ($s6 >> 2)),
2827              (int) (0xff & ($s6 >> 10)),
2828              (int) (0xff & (($s6 >> 18) | $s7 << 3)),
2829              (int) (0xff & ($s7 >> 5)),
2830              (int) (0xff & ($s7 >> 13)),
2831              (int) (0xff & ($s8 >> 0)),
2832              (int) (0xff & ($s8 >> 8)),
2833              (int) (0xff & (($s8 >> 16) | $s9 << 5)),
2834              (int) (0xff & ($s9 >> 3)),
2835              (int) (0xff & ($s9 >> 11)),
2836              (int) (0xff & (($s9 >> 19) | $s10 << 2)),
2837              (int) (0xff & ($s10 >> 6)),
2838              (int) (0xff & (($s10 >> 14) | $s11 << 7)),
2839              (int) (0xff & ($s11 >> 1)),
2840              (int) (0xff & ($s11 >> 9)),
2841              (int) (0xff & ($s11 >> 17))
2842          );
2843          return self::intArrayToString($arr);
2844      }
2845  
2846      /**
2847       * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
2848       *
2849       * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
2850       * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
2851       */
2852      public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A)
2853      {
2854          $aslide = array(
2855              13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
2856              0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
2857              0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
2858              0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
2859              0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
2860              0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
2861              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2862              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2863              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2864              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2865              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2866              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
2867          );
2868  
2869          /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
2870          $Ai = array();
2871  
2872          # ge_p3_to_cached(&Ai[0], A);
2873          $Ai[0] = self::ge_p3_to_cached($A);
2874          # ge_p3_dbl(&t, A);
2875          $t = self::ge_p3_dbl($A);
2876          # ge_p1p1_to_p3(&A2, &t);
2877          $A2 = self::ge_p1p1_to_p3($t);
2878  
2879          for ($i = 1; $i < 8; ++$i) {
2880              # ge_add(&t, &A2, &Ai[0]);
2881              $t = self::ge_add($A2, $Ai[$i - 1]);
2882              # ge_p1p1_to_p3(&u, &t);
2883              $u = self::ge_p1p1_to_p3($t);
2884              # ge_p3_to_cached(&Ai[i], &u);
2885              $Ai[$i] = self::ge_p3_to_cached($u);
2886          }
2887  
2888          $r = self::ge_p3_0();
2889          for ($i = 252; $i >= 0; --$i) {
2890              $t = self::ge_p3_dbl($r);
2891              if ($aslide[$i] > 0) {
2892                  # ge_p1p1_to_p3(&u, &t);
2893                  $u = self::ge_p1p1_to_p3($t);
2894                  # ge_add(&t, &u, &Ai[aslide[i] / 2]);
2895                  $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
2896              } elseif ($aslide[$i] < 0) {
2897                  # ge_p1p1_to_p3(&u, &t);
2898                  $u = self::ge_p1p1_to_p3($t);
2899                  # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
2900                  $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
2901              }
2902          }
2903  
2904          # ge_p1p1_to_p3(r, &t);
2905          return self::ge_p1p1_to_p3($t);
2906      }
2907  
2908      /**
2909       * @param string $a
2910       * @param string $b
2911       * @return string
2912       */
2913      public static function sc25519_mul($a, $b)
2914      {
2915          //    int64_t a0  = 2097151 & load_3(a);
2916          //    int64_t a1  = 2097151 & (load_4(a + 2) >> 5);
2917          //    int64_t a2  = 2097151 & (load_3(a + 5) >> 2);
2918          //    int64_t a3  = 2097151 & (load_4(a + 7) >> 7);
2919          //    int64_t a4  = 2097151 & (load_4(a + 10) >> 4);
2920          //    int64_t a5  = 2097151 & (load_3(a + 13) >> 1);
2921          //    int64_t a6  = 2097151 & (load_4(a + 15) >> 6);
2922          //    int64_t a7  = 2097151 & (load_3(a + 18) >> 3);
2923          //    int64_t a8  = 2097151 & load_3(a + 21);
2924          //    int64_t a9  = 2097151 & (load_4(a + 23) >> 5);
2925          //    int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
2926          //    int64_t a11 = (load_4(a + 28) >> 7);
2927          $a0  = 2097151 &  self::load_3(self::substr($a, 0, 3));
2928          $a1  = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
2929          $a2  = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
2930          $a3  = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
2931          $a4  = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
2932          $a5  = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
2933          $a6  = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
2934          $a7  = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
2935          $a8  = 2097151 &  self::load_3(self::substr($a, 21, 3));
2936          $a9  = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
2937          $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
2938          $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
2939  
2940          //    int64_t b0  = 2097151 & load_3(b);
2941          //    int64_t b1  = 2097151 & (load_4(b + 2) >> 5);
2942          //    int64_t b2  = 2097151 & (load_3(b + 5) >> 2);
2943          //    int64_t b3  = 2097151 & (load_4(b + 7) >> 7);
2944          //    int64_t b4  = 2097151 & (load_4(b + 10) >> 4);
2945          //    int64_t b5  = 2097151 & (load_3(b + 13) >> 1);
2946          //    int64_t b6  = 2097151 & (load_4(b + 15) >> 6);
2947          //    int64_t b7  = 2097151 & (load_3(b + 18) >> 3);
2948          //    int64_t b8  = 2097151 & load_3(b + 21);
2949          //    int64_t b9  = 2097151 & (load_4(b + 23) >> 5);
2950          //    int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
2951          //    int64_t b11 = (load_4(b + 28) >> 7);
2952          $b0  = 2097151 &  self::load_3(self::substr($b, 0, 3));
2953          $b1  = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
2954          $b2  = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
2955          $b3  = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
2956          $b4  = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
2957          $b5  = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
2958          $b6  = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
2959          $b7  = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
2960          $b8  = 2097151 &  self::load_3(self::substr($b, 21, 3));
2961          $b9  = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
2962          $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
2963          $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
2964  
2965          //    s0 = a0 * b0;
2966          //    s1 = a0 * b1 + a1 * b0;
2967          //    s2 = a0 * b2 + a1 * b1 + a2 * b0;
2968          //    s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
2969          //    s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
2970          //    s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
2971          //    s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
2972          //    s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
2973          //        a6 * b1 + a7 * b0;
2974          //    s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
2975          //        a6 * b2 + a7 * b1 + a8 * b0;
2976          //    s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
2977          //        a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
2978          //    s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
2979          //        a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
2980          //    s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
2981          //        a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
2982          //    s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 +
2983          //        a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
2984          //    s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 +
2985          //        a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
2986          //    s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 +
2987          //        a9 * b5 + a10 * b4 + a11 * b3;
2988          //    s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 +
2989          //        a10 * b5 + a11 * b4;
2990          //    s16 =
2991          //        a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
2992          //    s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
2993          //    s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
2994          //    s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
2995          //    s20 = a9 * b11 + a10 * b10 + a11 * b9;
2996          //    s21 = a10 * b11 + a11 * b10;
2997          //    s22 = a11 * b11;
2998          //    s23 = 0;
2999          $s0 = self::mul($a0, $b0, 22);
3000          $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22);
3001          $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22);
3002          $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22);
3003          $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) +
3004              self::mul($a4, $b0, 22);
3005          $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) +
3006              self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22);
3007          $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) +
3008              self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22);
3009          $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) +
3010              self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22);
3011          $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) +
3012              self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) +
3013              self::mul($a8, $b0, 22);
3014          $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) +
3015              self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) +
3016              self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22);
3017          $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) +
3018              self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) +
3019              self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22);
3020          $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) +
3021              self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) +
3022              self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22);
3023          $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) +
3024              self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) +
3025              self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22);
3026          $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) +
3027              self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) +
3028              self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22);
3029          $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) +
3030              self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) +
3031              self::mul($a11, $b3, 22);
3032          $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) +
3033              self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22);
3034          $s16 =
3035              self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) +
3036              self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22);
3037          $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) +
3038              self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22);
3039          $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22)
3040              + self::mul($a11, $b7, 22);
3041          $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) +
3042              self::mul($a11, $b8, 22);
3043          $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22);
3044          $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22);
3045          $s22 = self::mul($a11, $b11, 22);
3046          $s23 = 0;
3047  
3048          //    carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
3049          //    s1 += carry0;
3050          //    s0 -= carry0 * ((uint64_t) 1L << 21);
3051          $carry0 = ($s0 + (1 << 20)) >> 21;
3052          $s1 += $carry0;
3053          $s0 -= $carry0 << 21;
3054          //    carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
3055          //    s3 += carry2;
3056          //    s2 -= carry2 * ((uint64_t) 1L << 21);
3057          $carry2 = ($s2 + (1 << 20)) >> 21;
3058          $s3 += $carry2;
3059          $s2 -= $carry2 << 21;
3060          //    carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
3061          //    s5 += carry4;
3062          //    s4 -= carry4 * ((uint64_t) 1L << 21);
3063          $carry4 = ($s4 + (1 << 20)) >> 21;
3064          $s5 += $carry4;
3065          $s4 -= $carry4 << 21;
3066          //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
3067          //    s7 += carry6;
3068          //    s6 -= carry6 * ((uint64_t) 1L << 21);
3069          $carry6 = ($s6 + (1 << 20)) >> 21;
3070          $s7 += $carry6;
3071          $s6 -= $carry6 << 21;
3072          //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
3073          //    s9 += carry8;
3074          //    s8 -= carry8 * ((uint64_t) 1L << 21);
3075          $carry8 = ($s8 + (1 << 20)) >> 21;
3076          $s9 += $carry8;
3077          $s8 -= $carry8 << 21;
3078          //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
3079          //    s11 += carry10;
3080          //    s10 -= carry10 * ((uint64_t) 1L << 21);
3081          $carry10 = ($s10 + (1 << 20)) >> 21;
3082          $s11 += $carry10;
3083          $s10 -= $carry10 << 21;
3084          //    carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
3085          //    s13 += carry12;
3086          //    s12 -= carry12 * ((uint64_t) 1L << 21);
3087          $carry12 = ($s12 + (1 << 20)) >> 21;
3088          $s13 += $carry12;
3089          $s12 -= $carry12 << 21;
3090          //    carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
3091          //    s15 += carry14;
3092          //    s14 -= carry14 * ((uint64_t) 1L << 21);
3093          $carry14 = ($s14 + (1 << 20)) >> 21;
3094          $s15 += $carry14;
3095          $s14 -= $carry14 << 21;
3096          //    carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
3097          //    s17 += carry16;
3098          //    s16 -= carry16 * ((uint64_t) 1L << 21);
3099          $carry16 = ($s16 + (1 << 20)) >> 21;
3100          $s17 += $carry16;
3101          $s16 -= $carry16 << 21;
3102          //    carry18 = (s18 + (int64_t) (1L << 20)) >> 21;
3103          //    s19 += carry18;
3104          //    s18 -= carry18 * ((uint64_t) 1L << 21);
3105          $carry18 = ($s18 + (1 << 20)) >> 21;
3106          $s19 += $carry18;
3107          $s18 -= $carry18 << 21;
3108          //    carry20 = (s20 + (int64_t) (1L << 20)) >> 21;
3109          //    s21 += carry20;
3110          //    s20 -= carry20 * ((uint64_t) 1L << 21);
3111          $carry20 = ($s20 + (1 << 20)) >> 21;
3112          $s21 += $carry20;
3113          $s20 -= $carry20 << 21;
3114          //    carry22 = (s22 + (int64_t) (1L << 20)) >> 21;
3115          //    s23 += carry22;
3116          //    s22 -= carry22 * ((uint64_t) 1L << 21);
3117          $carry22 = ($s22 + (1 << 20)) >> 21;
3118          $s23 += $carry22;
3119          $s22 -= $carry22 << 21;
3120  
3121          //    carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
3122          //    s2 += carry1;
3123          //    s1 -= carry1 * ((uint64_t) 1L << 21);
3124          $carry1 = ($s1 + (1 << 20)) >> 21;
3125          $s2 += $carry1;
3126          $s1 -= $carry1 << 21;
3127          //    carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
3128          //    s4 += carry3;
3129          //    s3 -= carry3 * ((uint64_t) 1L << 21);
3130          $carry3 = ($s3 + (1 << 20)) >> 21;
3131          $s4 += $carry3;
3132          $s3 -= $carry3 << 21;
3133          //    carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
3134          //    s6 += carry5;
3135          //    s5 -= carry5 * ((uint64_t) 1L << 21);
3136          $carry5 = ($s5 + (1 << 20)) >> 21;
3137          $s6 += $carry5;
3138          $s5 -= $carry5 << 21;
3139          //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
3140          //    s8 += carry7;
3141          //    s7 -= carry7 * ((uint64_t) 1L << 21);
3142          $carry7 = ($s7 + (1 << 20)) >> 21;
3143          $s8 += $carry7;
3144          $s7 -= $carry7 << 21;
3145          //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
3146          //    s10 += carry9;
3147          //    s9 -= carry9 * ((uint64_t) 1L << 21);
3148          $carry9 = ($s9 + (1 << 20)) >> 21;
3149          $s10 += $carry9;
3150          $s9 -= $carry9 << 21;
3151          //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
3152          //    s12 += carry11;
3153          //    s11 -= carry11 * ((uint64_t) 1L << 21);
3154          $carry11 = ($s11 + (1 << 20)) >> 21;
3155          $s12 += $carry11;
3156          $s11 -= $carry11 << 21;
3157          //    carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
3158          //    s14 += carry13;
3159          //    s13 -= carry13 * ((uint64_t) 1L << 21);
3160          $carry13 = ($s13 + (1 << 20)) >> 21;
3161          $s14 += $carry13;
3162          $s13 -= $carry13 << 21;
3163          //    carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
3164          //    s16 += carry15;
3165          //    s15 -= carry15 * ((uint64_t) 1L << 21);
3166          $carry15 = ($s15 + (1 << 20)) >> 21;
3167          $s16 += $carry15;
3168          $s15 -= $carry15 << 21;
3169          //    carry17 = (s17 + (int64_t) (1L << 20)) >> 21;
3170          //    s18 += carry17;
3171          //    s17 -= carry17 * ((uint64_t) 1L << 21);
3172          $carry17 = ($s17 + (1 << 20)) >> 21;
3173          $s18 += $carry17;
3174          $s17 -= $carry17 << 21;
3175          //    carry19 = (s19 + (int64_t) (1L << 20)) >> 21;
3176          //    s20 += carry19;
3177          //    s19 -= carry19 * ((uint64_t) 1L << 21);
3178          $carry19 = ($s19 + (1 << 20)) >> 21;
3179          $s20 += $carry19;
3180          $s19 -= $carry19 << 21;
3181          //    carry21 = (s21 + (int64_t) (1L << 20)) >> 21;
3182          //    s22 += carry21;
3183          //    s21 -= carry21 * ((uint64_t) 1L << 21);
3184          $carry21 = ($s21 + (1 << 20)) >> 21;
3185          $s22 += $carry21;
3186          $s21 -= $carry21 << 21;
3187  
3188          //    s11 += s23 * 666643;
3189          //    s12 += s23 * 470296;
3190          //    s13 += s23 * 654183;
3191          //    s14 -= s23 * 997805;
3192          //    s15 += s23 * 136657;
3193          //    s16 -= s23 * 683901;
3194          $s11 += self::mul($s23, 666643, 20);
3195          $s12 += self::mul($s23, 470296, 19);
3196          $s13 += self::mul($s23, 654183, 20);
3197          $s14 -= self::mul($s23, 997805, 20);
3198          $s15 += self::mul($s23, 136657, 18);
3199          $s16 -= self::mul($s23, 683901, 20);
3200  
3201          //    s10 += s22 * 666643;
3202          //    s11 += s22 * 470296;
3203          //    s12 += s22 * 654183;
3204          //    s13 -= s22 * 997805;
3205          //    s14 += s22 * 136657;
3206          //    s15 -= s22 * 683901;
3207          $s10 += self::mul($s22, 666643, 20);
3208          $s11 += self::mul($s22, 470296, 19);
3209          $s12 += self::mul($s22, 654183, 20);
3210          $s13 -= self::mul($s22, 997805, 20);
3211          $s14 += self::mul($s22, 136657, 18);
3212          $s15 -= self::mul($s22, 683901, 20);
3213  
3214          //    s9 += s21 * 666643;
3215          //    s10 += s21 * 470296;
3216          //    s11 += s21 * 654183;
3217          //    s12 -= s21 * 997805;
3218          //    s13 += s21 * 136657;
3219          //    s14 -= s21 * 683901;
3220          $s9 += self::mul($s21, 666643, 20);
3221          $s10 += self::mul($s21, 470296, 19);
3222          $s11 += self::mul($s21, 654183, 20);
3223          $s12 -= self::mul($s21, 997805, 20);
3224          $s13 += self::mul($s21, 136657, 18);
3225          $s14 -= self::mul($s21, 683901, 20);
3226  
3227          //    s8 += s20 * 666643;
3228          //    s9 += s20 * 470296;
3229          //    s10 += s20 * 654183;
3230          //    s11 -= s20 * 997805;
3231          //    s12 += s20 * 136657;
3232          //    s13 -= s20 * 683901;
3233          $s8 += self::mul($s20, 666643, 20);
3234          $s9 += self::mul($s20, 470296, 19);
3235          $s10 += self::mul($s20, 654183, 20);
3236          $s11 -= self::mul($s20, 997805, 20);
3237          $s12 += self::mul($s20, 136657, 18);
3238          $s13 -= self::mul($s20, 683901, 20);
3239  
3240          //    s7 += s19 * 666643;
3241          //    s8 += s19 * 470296;
3242          //    s9 += s19 * 654183;
3243          //    s10 -= s19 * 997805;
3244          //    s11 += s19 * 136657;
3245          //    s12 -= s19 * 683901;
3246          $s7 += self::mul($s19, 666643, 20);
3247          $s8 += self::mul($s19, 470296, 19);
3248          $s9 += self::mul($s19, 654183, 20);
3249          $s10 -= self::mul($s19, 997805, 20);
3250          $s11 += self::mul($s19, 136657, 18);
3251          $s12 -= self::mul($s19, 683901, 20);
3252  
3253          //    s6 += s18 * 666643;
3254          //    s7 += s18 * 470296;
3255          //    s8 += s18 * 654183;
3256          //    s9 -= s18 * 997805;
3257          //    s10 += s18 * 136657;
3258          //    s11 -= s18 * 683901;
3259          $s6 += self::mul($s18, 666643, 20);
3260          $s7 += self::mul($s18, 470296, 19);
3261          $s8 += self::mul($s18, 654183, 20);
3262          $s9 -= self::mul($s18, 997805, 20);
3263          $s10 += self::mul($s18, 136657, 18);
3264          $s11 -= self::mul($s18, 683901, 20);
3265  
3266          //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
3267          //    s7 += carry6;
3268          //    s6 -= carry6 * ((uint64_t) 1L << 21);
3269          $carry6 = ($s6 + (1 << 20)) >> 21;
3270          $s7 += $carry6;
3271          $s6 -= $carry6 << 21;
3272          //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
3273          //    s9 += carry8;
3274          //    s8 -= carry8 * ((uint64_t) 1L << 21);
3275          $carry8 = ($s8 + (1 << 20)) >> 21;
3276          $s9 += $carry8;
3277          $s8 -= $carry8 << 21;
3278          //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
3279          //    s11 += carry10;
3280          //    s10 -= carry10 * ((uint64_t) 1L << 21);
3281          $carry10 = ($s10 + (1 << 20)) >> 21;
3282          $s11 += $carry10;
3283          $s10 -= $carry10 << 21;
3284          //    carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
3285          //    s13 += carry12;
3286          //    s12 -= carry12 * ((uint64_t) 1L << 21);
3287          $carry12 = ($s12 + (1 << 20)) >> 21;
3288          $s13 += $carry12;
3289          $s12 -= $carry12 << 21;
3290          //    carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
3291          //    s15 += carry14;
3292          //    s14 -= carry14 * ((uint64_t) 1L << 21);
3293          $carry14 = ($s14 + (1 << 20)) >> 21;
3294          $s15 += $carry14;
3295          $s14 -= $carry14 << 21;
3296          //    carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
3297          //    s17 += carry16;
3298          //    s16 -= carry16 * ((uint64_t) 1L << 21);
3299          $carry16 = ($s16 + (1 << 20)) >> 21;
3300          $s17 += $carry16;
3301          $s16 -= $carry16 << 21;
3302  
3303          //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
3304          //    s8 += carry7;
3305          //    s7 -= carry7 * ((uint64_t) 1L << 21);
3306          $carry7 = ($s7 + (1 << 20)) >> 21;
3307          $s8 += $carry7;
3308          $s7 -= $carry7 << 21;
3309          //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
3310          //    s10 += carry9;
3311          //    s9 -= carry9 * ((uint64_t) 1L << 21);
3312          $carry9 = ($s9 + (1 << 20)) >> 21;
3313          $s10 += $carry9;
3314          $s9 -= $carry9 << 21;
3315          //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
3316          //    s12 += carry11;
3317          //    s11 -= carry11 * ((uint64_t) 1L << 21);
3318          $carry11 = ($s11 + (1 << 20)) >> 21;
3319          $s12 += $carry11;
3320          $s11 -= $carry11 << 21;
3321          //    carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
3322          //    s14 += carry13;
3323          //    s13 -= carry13 * ((uint64_t) 1L << 21);
3324          $carry13 = ($s13 + (1 << 20)) >> 21;
3325          $s14 += $carry13;
3326          $s13 -= $carry13 << 21;
3327          //    carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
3328          //    s16 += carry15;
3329          //    s15 -= carry15 * ((uint64_t) 1L << 21);
3330          $carry15 = ($s15 + (1 << 20)) >> 21;
3331          $s16 += $carry15;
3332          $s15 -= $carry15 << 21;
3333  
3334          //    s5 += s17 * 666643;
3335          //    s6 += s17 * 470296;
3336          //    s7 += s17 * 654183;
3337          //    s8 -= s17 * 997805;
3338          //    s9 += s17 * 136657;
3339          //    s10 -= s17 * 683901;
3340          $s5 += self::mul($s17, 666643, 20);
3341          $s6 += self::mul($s17, 470296, 19);
3342          $s7 += self::mul($s17, 654183, 20);
3343          $s8 -= self::mul($s17, 997805, 20);
3344          $s9 += self::mul($s17, 136657, 18);
3345          $s10 -= self::mul($s17, 683901, 20);
3346  
3347          //    s4 += s16 * 666643;
3348          //    s5 += s16 * 470296;
3349          //    s6 += s16 * 654183;
3350          //    s7 -= s16 * 997805;
3351          //    s8 += s16 * 136657;
3352          //    s9 -= s16 * 683901;
3353          $s4 += self::mul($s16, 666643, 20);
3354          $s5 += self::mul($s16, 470296, 19);
3355          $s6 += self::mul($s16, 654183, 20);
3356          $s7 -= self::mul($s16, 997805, 20);
3357          $s8 += self::mul($s16, 136657, 18);
3358          $s9 -= self::mul($s16, 683901, 20);
3359  
3360          //    s3 += s15 * 666643;
3361          //    s4 += s15 * 470296;
3362          //    s5 += s15 * 654183;
3363          //    s6 -= s15 * 997805;
3364          //    s7 += s15 * 136657;
3365          //    s8 -= s15 * 683901;
3366          $s3 += self::mul($s15, 666643, 20);
3367          $s4 += self::mul($s15, 470296, 19);
3368          $s5 += self::mul($s15, 654183, 20);
3369          $s6 -= self::mul($s15, 997805, 20);
3370          $s7 += self::mul($s15, 136657, 18);
3371          $s8 -= self::mul($s15, 683901, 20);
3372  
3373          //    s2 += s14 * 666643;
3374          //    s3 += s14 * 470296;
3375          //    s4 += s14 * 654183;
3376          //    s5 -= s14 * 997805;
3377          //    s6 += s14 * 136657;
3378          //    s7 -= s14 * 683901;
3379          $s2 += self::mul($s14, 666643, 20);
3380          $s3 += self::mul($s14, 470296, 19);
3381          $s4 += self::mul($s14, 654183, 20);
3382          $s5 -= self::mul($s14, 997805, 20);
3383          $s6 += self::mul($s14, 136657, 18);
3384          $s7 -= self::mul($s14, 683901, 20);
3385  
3386          //    s1 += s13 * 666643;
3387          //    s2 += s13 * 470296;
3388          //    s3 += s13 * 654183;
3389          //    s4 -= s13 * 997805;
3390          //    s5 += s13 * 136657;
3391          //    s6 -= s13 * 683901;
3392          $s1 += self::mul($s13, 666643, 20);
3393          $s2 += self::mul($s13, 470296, 19);
3394          $s3 += self::mul($s13, 654183, 20);
3395          $s4 -= self::mul($s13, 997805, 20);
3396          $s5 += self::mul($s13, 136657, 18);
3397          $s6 -= self::mul($s13, 683901, 20);
3398  
3399          //    s0 += s12 * 666643;
3400          //    s1 += s12 * 470296;
3401          //    s2 += s12 * 654183;
3402          //    s3 -= s12 * 997805;
3403          //    s4 += s12 * 136657;
3404          //    s5 -= s12 * 683901;
3405          //    s12 = 0;
3406          $s0 += self::mul($s12, 666643, 20);
3407          $s1 += self::mul($s12, 470296, 19);
3408          $s2 += self::mul($s12, 654183, 20);
3409          $s3 -= self::mul($s12, 997805, 20);
3410          $s4 += self::mul($s12, 136657, 18);
3411          $s5 -= self::mul($s12, 683901, 20);
3412          $s12 = 0;
3413  
3414          //    carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
3415          //    s1 += carry0;
3416          //    s0 -= carry0 * ((uint64_t) 1L << 21);
3417          $carry0 = ($s0 + (1 << 20)) >> 21;
3418          $s1 += $carry0;
3419          $s0 -= $carry0 << 21;
3420          //    carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
3421          //    s3 += carry2;
3422          //    s2 -= carry2 * ((uint64_t) 1L << 21);
3423          $carry2 = ($s2 + (1 << 20)) >> 21;
3424          $s3 += $carry2;
3425          $s2 -= $carry2 << 21;
3426          //    carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
3427          //    s5 += carry4;
3428          //    s4 -= carry4 * ((uint64_t) 1L << 21);
3429          $carry4 = ($s4 + (1 << 20)) >> 21;
3430          $s5 += $carry4;
3431          $s4 -= $carry4 << 21;
3432          //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
3433          //    s7 += carry6;
3434          //    s6 -= carry6 * ((uint64_t) 1L << 21);
3435          $carry6 = ($s6 + (1 << 20)) >> 21;
3436          $s7 += $carry6;
3437          $s6 -= $carry6 << 21;
3438          //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
3439          //    s9 += carry8;
3440          //    s8 -= carry8 * ((uint64_t) 1L << 21);
3441          $carry8 = ($s8 + (1 << 20)) >> 21;
3442          $s9 += $carry8;
3443          $s8 -= $carry8 << 21;
3444          //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
3445          //    s11 += carry10;
3446          //    s10 -= carry10 * ((uint64_t) 1L << 21);
3447          $carry10 = ($s10 + (1 << 20)) >> 21;
3448          $s11 += $carry10;
3449          $s10 -= $carry10 << 21;
3450  
3451          //    carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
3452          //    s2 += carry1;
3453          //    s1 -= carry1 * ((uint64_t) 1L << 21);
3454          $carry1 = ($s1 + (1 << 20)) >> 21;
3455          $s2 += $carry1;
3456          $s1 -= $carry1 << 21;
3457          //    carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
3458          //    s4 += carry3;
3459          //    s3 -= carry3 * ((uint64_t) 1L << 21);
3460          $carry3 = ($s3 + (1 << 20)) >> 21;
3461          $s4 += $carry3;
3462          $s3 -= $carry3 << 21;
3463          //    carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
3464          //    s6 += carry5;
3465          //    s5 -= carry5 * ((uint64_t) 1L << 21);
3466          $carry5 = ($s5 + (1 << 20)) >> 21;
3467          $s6 += $carry5;
3468          $s5 -= $carry5 << 21;
3469          //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
3470          //    s8 += carry7;
3471          //    s7 -= carry7 * ((uint64_t) 1L << 21);
3472          $carry7 = ($s7 + (1 << 20)) >> 21;
3473          $s8 += $carry7;
3474          $s7 -= $carry7 << 21;
3475          //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
3476          //    s10 += carry9;
3477          //    s9 -= carry9 * ((uint64_t) 1L << 21);
3478          $carry9 = ($s9 + (1 << 20)) >> 21;
3479          $s10 += $carry9;
3480          $s9 -= $carry9 << 21;
3481          //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
3482          //    s12 += carry11;
3483          //    s11 -= carry11 * ((uint64_t) 1L << 21);
3484          $carry11 = ($s11 + (1 << 20)) >> 21;
3485          $s12 += $carry11;
3486          $s11 -= $carry11 << 21;
3487  
3488          //    s0 += s12 * 666643;
3489          //    s1 += s12 * 470296;
3490          //    s2 += s12 * 654183;
3491          //    s3 -= s12 * 997805;
3492          //    s4 += s12 * 136657;
3493          //    s5 -= s12 * 683901;
3494          //    s12 = 0;
3495          $s0 += self::mul($s12, 666643, 20);
3496          $s1 += self::mul($s12, 470296, 19);
3497          $s2 += self::mul($s12, 654183, 20);
3498          $s3 -= self::mul($s12, 997805, 20);
3499          $s4 += self::mul($s12, 136657, 18);
3500          $s5 -= self::mul($s12, 683901, 20);
3501          $s12 = 0;
3502  
3503          //    carry0 = s0 >> 21;
3504          //    s1 += carry0;
3505          //    s0 -= carry0 * ((uint64_t) 1L << 21);
3506          $carry0 = $s0 >> 21;
3507          $s1 += $carry0;
3508          $s0 -= $carry0 << 21;
3509          //    carry1 = s1 >> 21;
3510          //    s2 += carry1;
3511          //    s1 -= carry1 * ((uint64_t) 1L << 21);
3512          $carry1 = $s1 >> 21;
3513          $s2 += $carry1;
3514          $s1 -= $carry1 << 21;
3515          //    carry2 = s2 >> 21;
3516          //    s3 += carry2;
3517          //    s2 -= carry2 * ((uint64_t) 1L << 21);
3518          $carry2 = $s2 >> 21;
3519          $s3 += $carry2;
3520          $s2 -= $carry2 << 21;
3521          //    carry3 = s3 >> 21;
3522          //    s4 += carry3;
3523          //    s3 -= carry3 * ((uint64_t) 1L << 21);
3524          $carry3 = $s3 >> 21;
3525          $s4 += $carry3;
3526          $s3 -= $carry3 << 21;
3527          //    carry4 = s4 >> 21;
3528          //    s5 += carry4;
3529          //    s4 -= carry4 * ((uint64_t) 1L << 21);
3530          $carry4 = $s4 >> 21;
3531          $s5 += $carry4;
3532          $s4 -= $carry4 << 21;
3533          //    carry5 = s5 >> 21;
3534          //    s6 += carry5;
3535          //    s5 -= carry5 * ((uint64_t) 1L << 21);
3536          $carry5 = $s5 >> 21;
3537          $s6 += $carry5;
3538          $s5 -= $carry5 << 21;
3539          //    carry6 = s6 >> 21;
3540          //    s7 += carry6;
3541          //    s6 -= carry6 * ((uint64_t) 1L << 21);
3542          $carry6 = $s6 >> 21;
3543          $s7 += $carry6;
3544          $s6 -= $carry6 << 21;
3545          //    carry7 = s7 >> 21;
3546          //    s8 += carry7;
3547          //    s7 -= carry7 * ((uint64_t) 1L << 21);
3548          $carry7 = $s7 >> 21;
3549          $s8 += $carry7;
3550          $s7 -= $carry7 << 21;
3551          //    carry8 = s8 >> 21;
3552          //    s9 += carry8;
3553          //    s8 -= carry8 * ((uint64_t) 1L << 21);
3554          $carry8 = $s8 >> 21;
3555          $s9 += $carry8;
3556          $s8 -= $carry8 << 21;
3557          //    carry9 = s9 >> 21;
3558          //    s10 += carry9;
3559          //    s9 -= carry9 * ((uint64_t) 1L << 21);
3560          $carry9 = $s9 >> 21;
3561          $s10 += $carry9;
3562          $s9 -= $carry9 << 21;
3563          //    carry10 = s10 >> 21;
3564          //    s11 += carry10;
3565          //    s10 -= carry10 * ((uint64_t) 1L << 21);
3566          $carry10 = $s10 >> 21;
3567          $s11 += $carry10;
3568          $s10 -= $carry10 << 21;
3569          //    carry11 = s11 >> 21;
3570          //    s12 += carry11;
3571          //    s11 -= carry11 * ((uint64_t) 1L << 21);
3572          $carry11 = $s11 >> 21;
3573          $s12 += $carry11;
3574          $s11 -= $carry11 << 21;
3575  
3576          //    s0 += s12 * 666643;
3577          //    s1 += s12 * 470296;
3578          //    s2 += s12 * 654183;
3579          //    s3 -= s12 * 997805;
3580          //    s4 += s12 * 136657;
3581          //    s5 -= s12 * 683901;
3582          $s0 += self::mul($s12, 666643, 20);
3583          $s1 += self::mul($s12, 470296, 19);
3584          $s2 += self::mul($s12, 654183, 20);
3585          $s3 -= self::mul($s12, 997805, 20);
3586          $s4 += self::mul($s12, 136657, 18);
3587          $s5 -= self::mul($s12, 683901, 20);
3588  
3589          //    carry0 = s0 >> 21;
3590          //    s1 += carry0;
3591          //    s0 -= carry0 * ((uint64_t) 1L << 21);
3592          $carry0 = $s0 >> 21;
3593          $s1 += $carry0;
3594          $s0 -= $carry0 << 21;
3595          //    carry1 = s1 >> 21;
3596          //    s2 += carry1;
3597          //    s1 -= carry1 * ((uint64_t) 1L << 21);
3598          $carry1 = $s1 >> 21;
3599          $s2 += $carry1;
3600          $s1 -= $carry1 << 21;
3601          //    carry2 = s2 >> 21;
3602          //    s3 += carry2;
3603          //    s2 -= carry2 * ((uint64_t) 1L << 21);
3604          $carry2 = $s2 >> 21;
3605          $s3 += $carry2;
3606          $s2 -= $carry2 << 21;
3607          //    carry3 = s3 >> 21;
3608          //    s4 += carry3;
3609          //    s3 -= carry3 * ((uint64_t) 1L << 21);
3610          $carry3 = $s3 >> 21;
3611          $s4 += $carry3;
3612          $s3 -= $carry3 << 21;
3613          //    carry4 = s4 >> 21;
3614          //    s5 += carry4;
3615          //    s4 -= carry4 * ((uint64_t) 1L << 21);
3616          $carry4 = $s4 >> 21;
3617          $s5 += $carry4;
3618          $s4 -= $carry4 << 21;
3619          //    carry5 = s5 >> 21;
3620          //    s6 += carry5;
3621          //    s5 -= carry5 * ((uint64_t) 1L << 21);
3622          $carry5 = $s5 >> 21;
3623          $s6 += $carry5;
3624          $s5 -= $carry5 << 21;
3625          //    carry6 = s6 >> 21;
3626          //    s7 += carry6;
3627          //    s6 -= carry6 * ((uint64_t) 1L << 21);
3628          $carry6 = $s6 >> 21;
3629          $s7 += $carry6;
3630          $s6 -= $carry6 << 21;
3631          //    carry7 = s7 >> 21;
3632          //    s8 += carry7;
3633          //    s7 -= carry7 * ((uint64_t) 1L << 21);
3634          $carry7 = $s7 >> 21;
3635          $s8 += $carry7;
3636          $s7 -= $carry7 << 21;
3637          //    carry8 = s8 >> 21;
3638          //    s9 += carry8;
3639          //    s8 -= carry8 * ((uint64_t) 1L << 21);
3640          $carry8 = $s8 >> 21;
3641          $s9 += $carry8;
3642          $s8 -= $carry8 << 21;
3643          //    carry9 = s9 >> 21;
3644          //    s10 += carry9;
3645          //    s9 -= carry9 * ((uint64_t) 1L << 21);
3646          $carry9 = $s9 >> 21;
3647          $s10 += $carry9;
3648          $s9 -= $carry9 << 21;
3649          //    carry10 = s10 >> 21;
3650          //    s11 += carry10;
3651          //    s10 -= carry10 * ((uint64_t) 1L << 21);
3652          $carry10 = $s10 >> 21;
3653          $s11 += $carry10;
3654          $s10 -= $carry10 << 21;
3655  
3656          $s = array_fill(0, 32, 0);
3657          // s[0]  = s0 >> 0;
3658          $s[0]  = $s0 >> 0;
3659          // s[1]  = s0 >> 8;
3660          $s[1]  = $s0 >> 8;
3661          // s[2]  = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5));
3662          $s[2]  = ($s0 >> 16) | ($s1 << 5);
3663          // s[3]  = s1 >> 3;
3664          $s[3]  = $s1 >> 3;
3665          // s[4]  = s1 >> 11;
3666          $s[4]  = $s1 >> 11;
3667          // s[5]  = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2));
3668          $s[5]  = ($s1 >> 19) | ($s2 << 2);
3669          // s[6]  = s2 >> 6;
3670          $s[6]  = $s2 >> 6;
3671          // s[7]  = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7));
3672          $s[7]  = ($s2 >> 14) | ($s3 << 7);
3673          // s[8]  = s3 >> 1;
3674          $s[8]  = $s3 >> 1;
3675          // s[9]  = s3 >> 9;
3676          $s[9]  = $s3 >> 9;
3677          // s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4));
3678          $s[10] = ($s3 >> 17) | ($s4 << 4);
3679          // s[11] = s4 >> 4;
3680          $s[11] = $s4 >> 4;
3681          // s[12] = s4 >> 12;
3682          $s[12] = $s4 >> 12;
3683          // s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1));
3684          $s[13] = ($s4 >> 20) | ($s5 << 1);
3685          // s[14] = s5 >> 7;
3686          $s[14] = $s5 >> 7;
3687          // s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6));
3688          $s[15] = ($s5 >> 15) | ($s6 << 6);
3689          // s[16] = s6 >> 2;
3690          $s[16] = $s6 >> 2;
3691          // s[17] = s6 >> 10;
3692          $s[17] = $s6 >> 10;
3693          // s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3));
3694          $s[18] = ($s6 >> 18) | ($s7 << 3);
3695          // s[19] = s7 >> 5;
3696          $s[19] = $s7 >> 5;
3697          // s[20] = s7 >> 13;
3698          $s[20] = $s7 >> 13;
3699          // s[21] = s8 >> 0;
3700          $s[21] = $s8 >> 0;
3701          // s[22] = s8 >> 8;
3702          $s[22] = $s8 >> 8;
3703          // s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5));
3704          $s[23] = ($s8 >> 16) | ($s9 << 5);
3705          // s[24] = s9 >> 3;
3706          $s[24] = $s9 >> 3;
3707          // s[25] = s9 >> 11;
3708          $s[25] = $s9 >> 11;
3709          // s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2));
3710          $s[26] = ($s9 >> 19) | ($s10 << 2);
3711          // s[27] = s10 >> 6;
3712          $s[27] = $s10 >> 6;
3713          // s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7));
3714          $s[28] = ($s10 >> 14) | ($s11 << 7);
3715          // s[29] = s11 >> 1;
3716          $s[29] = $s11 >> 1;
3717          // s[30] = s11 >> 9;
3718          $s[30] = $s11 >> 9;
3719          // s[31] = s11 >> 17;
3720          $s[31] = $s11 >> 17;
3721          return self::intArrayToString($s);
3722      }
3723  
3724      /**
3725       * @param string $s
3726       * @return string
3727       */
3728      public static function sc25519_sq($s)
3729      {
3730          return self::sc25519_mul($s, $s);
3731      }
3732  
3733      /**
3734       * @param string $s
3735       * @param int $n
3736       * @param string $a
3737       * @return string
3738       */
3739      public static function sc25519_sqmul($s, $n, $a)
3740      {
3741          for ($i = 0; $i < $n; ++$i) {
3742              $s = self::sc25519_sq($s);
3743          }
3744          return self::sc25519_mul($s, $a);
3745      }
3746  
3747      /**
3748       * @param string $s
3749       * @return string
3750       */
3751      public static function sc25519_invert($s)
3752      {
3753          $_10 = self::sc25519_sq($s);
3754          $_11 = self::sc25519_mul($s, $_10);
3755          $_100 = self::sc25519_mul($s, $_11);
3756          $_1000 = self::sc25519_sq($_100);
3757          $_1010 = self::sc25519_mul($_10, $_1000);
3758          $_1011 = self::sc25519_mul($s, $_1010);
3759          $_10000 = self::sc25519_sq($_1000);
3760          $_10110 = self::sc25519_sq($_1011);
3761          $_100000 = self::sc25519_mul($_1010, $_10110);
3762          $_100110 = self::sc25519_mul($_10000, $_10110);
3763          $_1000000 = self::sc25519_sq($_100000);
3764          $_1010000 = self::sc25519_mul($_10000, $_1000000);
3765          $_1010011 = self::sc25519_mul($_11, $_1010000);
3766          $_1100011 = self::sc25519_mul($_10000, $_1010011);
3767          $_1100111 = self::sc25519_mul($_100, $_1100011);
3768          $_1101011 = self::sc25519_mul($_100, $_1100111);
3769          $_10010011 = self::sc25519_mul($_1000000, $_1010011);
3770          $_10010111 = self::sc25519_mul($_100, $_10010011);
3771          $_10111101 = self::sc25519_mul($_100110, $_10010111);
3772          $_11010011 = self::sc25519_mul($_10110, $_10111101);
3773          $_11100111 = self::sc25519_mul($_1010000, $_10010111);
3774          $_11101011 = self::sc25519_mul($_100, $_11100111);
3775          $_11110101 = self::sc25519_mul($_1010, $_11101011);
3776  
3777          $recip = self::sc25519_mul($_1011, $_11110101);
3778          $recip = self::sc25519_sqmul($recip, 126, $_1010011);
3779          $recip = self::sc25519_sqmul($recip, 9, $_10);
3780          $recip = self::sc25519_mul($recip, $_11110101);
3781          $recip = self::sc25519_sqmul($recip, 7, $_1100111);
3782          $recip = self::sc25519_sqmul($recip, 9, $_11110101);
3783          $recip = self::sc25519_sqmul($recip, 11, $_10111101);
3784          $recip = self::sc25519_sqmul($recip, 8, $_11100111);
3785          $recip = self::sc25519_sqmul($recip, 9, $_1101011);
3786          $recip = self::sc25519_sqmul($recip, 6, $_1011);
3787          $recip = self::sc25519_sqmul($recip, 14, $_10010011);
3788          $recip = self::sc25519_sqmul($recip, 10, $_1100011);
3789          $recip = self::sc25519_sqmul($recip, 9, $_10010111);
3790          $recip = self::sc25519_sqmul($recip, 10, $_11110101);
3791          $recip = self::sc25519_sqmul($recip, 8, $_11010011);
3792          return self::sc25519_sqmul($recip, 8, $_11101011);
3793      }
3794  
3795      /**
3796       * @param string $s
3797       * @return string
3798       */
3799      public static function clamp($s)
3800      {
3801          $s_ = self::stringToIntArray($s);
3802          $s_[0] &= 248;
3803          $s_[31] |= 64;
3804          $s_[31] &= 127;
3805          return self::intArrayToString($s_);
3806      }
3807  
3808      /**
3809       * Ensure limbs are less than 28 bits long to prevent float promotion.
3810       *
3811       * This uses a constant-time conditional swap under the hood.
3812       *
3813       * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
3814       * @return ParagonIE_Sodium_Core_Curve25519_Fe
3815       */
3816      public static function fe_normalize(ParagonIE_Sodium_Core_Curve25519_Fe $f)
3817      {
3818          $x = (PHP_INT_SIZE << 3) - 1; // 31 or 63
3819  
3820          $g = self::fe_copy($f);
3821          $e = array(
3822              $g->e0, $g->e1, $g->e2, $g->e3, $g->e4,
3823              $g->e5, $g->e6, $g->e7, $g->e8, $g->e9
3824          );
3825          for ($i = 0; $i < 10; ++$i) {
3826              $mask = -(($e[$i] >> $x) & 1);
3827  
3828              /*
3829               * Get two candidate normalized values for $e[$i], depending on the sign of $e[$i]:
3830               */
3831              $a = $e[$i] & 0x7ffffff;
3832              $b = -((-$e[$i]) & 0x7ffffff);
3833  
3834              /*
3835               * Return the appropriate candidate value, based on the sign of the original input:
3836               *
3837               * The following is equivalent to this ternary:
3838               *
3839               * $e[$i] = (($e[$i] >> $x) & 1) ? $a : $b;
3840               *
3841               * Except what's written doesn't contain timing leaks.
3842               */
3843              $e[$i] = ($a ^ (($a ^ $b) & $mask));
3844          }
3845          $g->e0 = $e[0];
3846          $g->e1 = $e[1];
3847          $g->e2 = $e[2];
3848          $g->e3 = $e[3];
3849          $g->e4 = $e[4];
3850          $g->e5 = $e[5];
3851          $g->e6 = $e[6];
3852          $g->e7 = $e[7];
3853          $g->e8 = $e[8];
3854          $g->e9 = $e[9];
3855          return $g;
3856      }
3857  }


Generated : Fri Oct 10 08:20:03 2025 Cross-referenced by PHPXref