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


Generated : Wed Dec 25 08:20:01 2024 Cross-referenced by PHPXref