summaryrefslogtreecommitdiffstats
path: root/vendor/paragonie/sodium_compat/src/Core/Curve25519.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/paragonie/sodium_compat/src/Core/Curve25519.php7942
1 files changed, 3836 insertions, 4106 deletions
diff --git a/vendor/paragonie/sodium_compat/src/Core/Curve25519.php b/vendor/paragonie/sodium_compat/src/Core/Curve25519.php
index f0b9c5f..dfcf26a 100644
--- a/vendor/paragonie/sodium_compat/src/Core/Curve25519.php
+++ b/vendor/paragonie/sodium_compat/src/Core/Curve25519.php
@@ -1,4106 +1,3836 @@
-<?php
-
-if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
- return;
-}
-
-/**
- * Class ParagonIE_Sodium_Core_Curve25519
- *
- * Implements Curve25519 core functions
- *
- * Based on the ref10 curve25519 code provided by libsodium
- *
- * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
- */
-abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Curve25519_H
-{
- /**
- * Get a field element of size 10 with a value of 0
- *
- * @internal You should not use this directly from another application
- *
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_0()
- {
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
- );
- }
-
- /**
- * Get a field element of size 10 with a value of 1
- *
- * @internal You should not use this directly from another application
- *
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_1()
- {
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
- );
- }
-
- /**
- * Add two field elements.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- * @psalm-suppress MixedAssignment
- * @psalm-suppress MixedOperand
- */
- public static function fe_add(
- ParagonIE_Sodium_Core_Curve25519_Fe $f,
- ParagonIE_Sodium_Core_Curve25519_Fe $g
- ) {
- /** @var array<int, int> $arr */
- $arr = array();
- for ($i = 0; $i < 10; ++$i) {
- $arr[$i] = (int) ($f[$i] + $g[$i]);
- }
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr);
- }
-
- /**
- * Constant-time conditional move.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
- * @param int $b
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- * @psalm-suppress MixedAssignment
- */
- public static function fe_cmov(
- ParagonIE_Sodium_Core_Curve25519_Fe $f,
- ParagonIE_Sodium_Core_Curve25519_Fe $g,
- $b = 0
- ) {
- /** @var array<int, int> $h */
- $h = array();
- $b *= -1;
- for ($i = 0; $i < 10; ++$i) {
- $x = (($f[$i] ^ $g[$i]) & $b);
- $h[$i] = ($f[$i]) ^ $x;
- }
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
- }
-
- /**
- * Create a copy of a field element.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- $h = clone $f;
- return $h;
- }
-
- /**
- * Give: 32-byte string.
- * Receive: A field element object to use for internal calculations.
- *
- * @internal You should not use this directly from another application
- *
- * @param string $s
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- * @throws RangeException
- * @throws TypeError
- */
- public static function fe_frombytes($s)
- {
- if (self::strlen($s) !== 32) {
- throw new RangeException('Expected a 32-byte string.');
- }
- /** @var int $h0 */
- $h0 = self::load_4($s);
- /** @var int $h1 */
- $h1 = self::load_3(self::substr($s, 4, 3)) << 6;
- /** @var int $h2 */
- $h2 = self::load_3(self::substr($s, 7, 3)) << 5;
- /** @var int $h3 */
- $h3 = self::load_3(self::substr($s, 10, 3)) << 3;
- /** @var int $h4 */
- $h4 = self::load_3(self::substr($s, 13, 3)) << 2;
- /** @var int $h5 */
- $h5 = self::load_4(self::substr($s, 16, 4));
- /** @var int $h6 */
- $h6 = self::load_3(self::substr($s, 20, 3)) << 7;
- /** @var int $h7 */
- $h7 = self::load_3(self::substr($s, 23, 3)) << 5;
- /** @var int $h8 */
- $h8 = self::load_3(self::substr($s, 26, 3)) << 4;
- /** @var int $h9 */
- $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2;
-
- /** @var int $carry9 */
- $carry9 = ($h9 + (1 << 24)) >> 25;
- $h0 += self::mul($carry9, 19, 5);
- $h9 -= $carry9 << 25;
- /** @var int $carry1 */
- $carry1 = ($h1 + (1 << 24)) >> 25;
- $h2 += $carry1;
- $h1 -= $carry1 << 25;
- /** @var int $carry3 */
- $carry3 = ($h3 + (1 << 24)) >> 25;
- $h4 += $carry3;
- $h3 -= $carry3 << 25;
- /** @var int $carry5 */
- $carry5 = ($h5 + (1 << 24)) >> 25;
- $h6 += $carry5;
- $h5 -= $carry5 << 25;
- /** @var int $carry7 */
- $carry7 = ($h7 + (1 << 24)) >> 25;
- $h8 += $carry7;
- $h7 -= $carry7 << 25;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
- /** @var int $carry2 */
- $carry2 = ($h2 + (1 << 25)) >> 26;
- $h3 += $carry2;
- $h2 -= $carry2 << 26;
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
- /** @var int $carry6 */
- $carry6 = ($h6 + (1 << 25)) >> 26;
- $h7 += $carry6;
- $h6 -= $carry6 << 26;
- /** @var int $carry8 */
- $carry8 = ($h8 + (1 << 25)) >> 26;
- $h9 += $carry8;
- $h8 -= $carry8 << 26;
-
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(
- (int) $h0,
- (int) $h1,
- (int) $h2,
- (int) $h3,
- (int) $h4,
- (int) $h5,
- (int) $h6,
- (int) $h7,
- (int) $h8,
- (int) $h9
- )
- );
- }
-
- /**
- * Convert a field element to a byte string.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $h
- * @return string
- */
- public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h)
- {
- /** @var int $h0 */
- $h0 = (int) $h[0];
- /** @var int $h1 */
- $h1 = (int) $h[1];
- /** @var int $h2 */
- $h2 = (int) $h[2];
- /** @var int $h3 */
- $h3 = (int) $h[3];
- /** @var int $h4 */
- $h4 = (int) $h[4];
- /** @var int $h5 */
- $h5 = (int) $h[5];
- /** @var int $h6 */
- $h6 = (int) $h[6];
- /** @var int $h7 */
- $h7 = (int) $h[7];
- /** @var int $h8 */
- $h8 = (int) $h[8];
- /** @var int $h9 */
- $h9 = (int) $h[9];
-
- /** @var int $q */
- $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
- /** @var int $q */
- $q = ($h0 + $q) >> 26;
- /** @var int $q */
- $q = ($h1 + $q) >> 25;
- /** @var int $q */
- $q = ($h2 + $q) >> 26;
- /** @var int $q */
- $q = ($h3 + $q) >> 25;
- /** @var int $q */
- $q = ($h4 + $q) >> 26;
- /** @var int $q */
- $q = ($h5 + $q) >> 25;
- /** @var int $q */
- $q = ($h6 + $q) >> 26;
- /** @var int $q */
- $q = ($h7 + $q) >> 25;
- /** @var int $q */
- $q = ($h8 + $q) >> 26;
- /** @var int $q */
- $q = ($h9 + $q) >> 25;
-
- $h0 += self::mul($q, 19, 5);
-
- /** @var int $carry0 */
- $carry0 = $h0 >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
- /** @var int $carry1 */
- $carry1 = $h1 >> 25;
- $h2 += $carry1;
- $h1 -= $carry1 << 25;
- /** @var int $carry2 */
- $carry2 = $h2 >> 26;
- $h3 += $carry2;
- $h2 -= $carry2 << 26;
- /** @var int $carry3 */
- $carry3 = $h3 >> 25;
- $h4 += $carry3;
- $h3 -= $carry3 << 25;
- /** @var int $carry4 */
- $carry4 = $h4 >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
- /** @var int $carry5 */
- $carry5 = $h5 >> 25;
- $h6 += $carry5;
- $h5 -= $carry5 << 25;
- /** @var int $carry6 */
- $carry6 = $h6 >> 26;
- $h7 += $carry6;
- $h6 -= $carry6 << 26;
- /** @var int $carry7 */
- $carry7 = $h7 >> 25;
- $h8 += $carry7;
- $h7 -= $carry7 << 25;
- /** @var int $carry8 */
- $carry8 = $h8 >> 26;
- $h9 += $carry8;
- $h8 -= $carry8 << 26;
- /** @var int $carry9 */
- $carry9 = $h9 >> 25;
- $h9 -= $carry9 << 25;
-
- /**
- * @var array<int, int>
- */
- $s = array(
- (int) (($h0 >> 0) & 0xff),
- (int) (($h0 >> 8) & 0xff),
- (int) (($h0 >> 16) & 0xff),
- (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
- (int) (($h1 >> 6) & 0xff),
- (int) (($h1 >> 14) & 0xff),
- (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
- (int) (($h2 >> 5) & 0xff),
- (int) (($h2 >> 13) & 0xff),
- (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
- (int) (($h3 >> 3) & 0xff),
- (int) (($h3 >> 11) & 0xff),
- (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
- (int) (($h4 >> 2) & 0xff),
- (int) (($h4 >> 10) & 0xff),
- (int) (($h4 >> 18) & 0xff),
- (int) (($h5 >> 0) & 0xff),
- (int) (($h5 >> 8) & 0xff),
- (int) (($h5 >> 16) & 0xff),
- (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
- (int) (($h6 >> 7) & 0xff),
- (int) (($h6 >> 15) & 0xff),
- (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
- (int) (($h7 >> 5) & 0xff),
- (int) (($h7 >> 13) & 0xff),
- (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
- (int) (($h8 >> 4) & 0xff),
- (int) (($h8 >> 12) & 0xff),
- (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
- (int) (($h9 >> 2) & 0xff),
- (int) (($h9 >> 10) & 0xff),
- (int) (($h9 >> 18) & 0xff)
- );
- return self::intArrayToString($s);
- }
-
- /**
- * Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return int
- * @throws SodiumException
- * @throws TypeError
- */
- public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- $str = self::fe_tobytes($f);
- return (int) (self::chrToInt($str[0]) & 1);
- }
-
- /**
- * Returns 0 if this field element results in all NUL bytes.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return bool
- * @throws SodiumException
- * @throws TypeError
- */
- public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- static $zero;
- if ($zero === null) {
- $zero = str_repeat("\x00", 32);
- }
- /** @var string $zero */
- /** @var string $str */
- $str = self::fe_tobytes($f);
- return !self::verify_32($str, (string) $zero);
- }
-
- /**
- * Multiply two field elements
- *
- * h = f * g
- *
- * @internal You should not use this directly from another application
- *
- * @security Is multiplication a source of timing leaks? If so, can we do
- * anything to prevent that from happening?
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_mul(
- ParagonIE_Sodium_Core_Curve25519_Fe $f,
- ParagonIE_Sodium_Core_Curve25519_Fe $g
- ) {
- /** @var int $f0 */
- $f0 = $f[0];
- /** @var int $f1 */
- $f1 = $f[1];
- /** @var int $f2 */
- $f2 = $f[2];
- /** @var int $f3 */
- $f3 = $f[3];
- /** @var int $f4 */
- $f4 = $f[4];
- /** @var int $f5 */
- $f5 = $f[5];
- /** @var int $f6 */
- $f6 = $f[6];
- /** @var int $f7 */
- $f7 = $f[7];
- /** @var int $f8 */
- $f8 = $f[8];
- /** @var int $f9 */
- $f9 = $f[9];
- /** @var int $g0 */
- $g0 = $g[0];
- /** @var int $g1 */
- $g1 = $g[1];
- /** @var int $g2 */
- $g2 = $g[2];
- /** @var int $g3 */
- $g3 = $g[3];
- /** @var int $g4 */
- $g4 = $g[4];
- /** @var int $g5 */
- $g5 = $g[5];
- /** @var int $g6 */
- $g6 = $g[6];
- /** @var int $g7 */
- $g7 = $g[7];
- /** @var int $g8 */
- $g8 = $g[8];
- /** @var int $g9 */
- $g9 = $g[9];
- $g1_19 = self::mul($g1, 19, 5);
- $g2_19 = self::mul($g2, 19, 5);
- $g3_19 = self::mul($g3, 19, 5);
- $g4_19 = self::mul($g4, 19, 5);
- $g5_19 = self::mul($g5, 19, 5);
- $g6_19 = self::mul($g6, 19, 5);
- $g7_19 = self::mul($g7, 19, 5);
- $g8_19 = self::mul($g8, 19, 5);
- $g9_19 = self::mul($g9, 19, 5);
- /** @var int $f1_2 */
- $f1_2 = $f1 << 1;
- /** @var int $f3_2 */
- $f3_2 = $f3 << 1;
- /** @var int $f5_2 */
- $f5_2 = $f5 << 1;
- /** @var int $f7_2 */
- $f7_2 = $f7 << 1;
- /** @var int $f9_2 */
- $f9_2 = $f9 << 1;
- $f0g0 = self::mul($f0, $g0, 26);
- $f0g1 = self::mul($f0, $g1, 25);
- $f0g2 = self::mul($f0, $g2, 26);
- $f0g3 = self::mul($f0, $g3, 25);
- $f0g4 = self::mul($f0, $g4, 26);
- $f0g5 = self::mul($f0, $g5, 25);
- $f0g6 = self::mul($f0, $g6, 26);
- $f0g7 = self::mul($f0, $g7, 25);
- $f0g8 = self::mul($f0, $g8, 26);
- $f0g9 = self::mul($f0, $g9, 26);
- $f1g0 = self::mul($f1, $g0, 26);
- $f1g1_2 = self::mul($f1_2, $g1, 25);
- $f1g2 = self::mul($f1, $g2, 26);
- $f1g3_2 = self::mul($f1_2, $g3, 25);
- $f1g4 = self::mul($f1, $g4, 26);
- $f1g5_2 = self::mul($f1_2, $g5, 25);
- $f1g6 = self::mul($f1, $g6, 26);
- $f1g7_2 = self::mul($f1_2, $g7, 25);
- $f1g8 = self::mul($f1, $g8, 26);
- $f1g9_38 = self::mul($g9_19, $f1_2, 26);
- $f2g0 = self::mul($f2, $g0, 26);
- $f2g1 = self::mul($f2, $g1, 25);
- $f2g2 = self::mul($f2, $g2, 26);
- $f2g3 = self::mul($f2, $g3, 25);
- $f2g4 = self::mul($f2, $g4, 26);
- $f2g5 = self::mul($f2, $g5, 25);
- $f2g6 = self::mul($f2, $g6, 26);
- $f2g7 = self::mul($f2, $g7, 25);
- $f2g8_19 = self::mul($g8_19, $f2, 26);
- $f2g9_19 = self::mul($g9_19, $f2, 26);
- $f3g0 = self::mul($f3, $g0, 26);
- $f3g1_2 = self::mul($f3_2, $g1, 25);
- $f3g2 = self::mul($f3, $g2, 26);
- $f3g3_2 = self::mul($f3_2, $g3, 25);
- $f3g4 = self::mul($f3, $g4, 26);
- $f3g5_2 = self::mul($f3_2, $g5, 25);
- $f3g6 = self::mul($f3, $g6, 26);
- $f3g7_38 = self::mul($g7_19, $f3_2, 26);
- $f3g8_19 = self::mul($g8_19, $f3, 25);
- $f3g9_38 = self::mul($g9_19, $f3_2, 26);
- $f4g0 = self::mul($f4, $g0, 26);
- $f4g1 = self::mul($f4, $g1, 25);
- $f4g2 = self::mul($f4, $g2, 26);
- $f4g3 = self::mul($f4, $g3, 25);
- $f4g4 = self::mul($f4, $g4, 26);
- $f4g5 = self::mul($f4, $g5, 25);
- $f4g6_19 = self::mul($g6_19, $f4, 26);
- $f4g7_19 = self::mul($g7_19, $f4, 26);
- $f4g8_19 = self::mul($g8_19, $f4, 26);
- $f4g9_19 = self::mul($g9_19, $f4, 26);
- $f5g0 = self::mul($f5, $g0, 26);
- $f5g1_2 = self::mul($f5_2, $g1, 25);
- $f5g2 = self::mul($f5, $g2, 26);
- $f5g3_2 = self::mul($f5_2, $g3, 25);
- $f5g4 = self::mul($f5, $g4, 26);
- $f5g5_38 = self::mul($g5_19, $f5_2, 26);
- $f5g6_19 = self::mul($g6_19, $f5, 25);
- $f5g7_38 = self::mul($g7_19, $f5_2, 26);
- $f5g8_19 = self::mul($g8_19, $f5, 25);
- $f5g9_38 = self::mul($g9_19, $f5_2, 26);
- $f6g0 = self::mul($f6, $g0, 26);
- $f6g1 = self::mul($f6, $g1, 25);
- $f6g2 = self::mul($f6, $g2, 26);
- $f6g3 = self::mul($f6, $g3, 25);
- $f6g4_19 = self::mul($g4_19, $f6, 26);
- $f6g5_19 = self::mul($g5_19, $f6, 26);
- $f6g6_19 = self::mul($g6_19, $f6, 26);
- $f6g7_19 = self::mul($g7_19, $f6, 26);
- $f6g8_19 = self::mul($g8_19, $f6, 26);
- $f6g9_19 = self::mul($g9_19, $f6, 26);
- $f7g0 = self::mul($f7, $g0, 26);
- $f7g1_2 = self::mul($f7_2, $g1, 25);
- $f7g2 = self::mul($f7, $g2, 26);
- $f7g3_38 = self::mul($g3_19, $f7_2, 26);
- $f7g4_19 = self::mul($g4_19, $f7, 26);
- $f7g5_38 = self::mul($g5_19, $f7_2, 26);
- $f7g6_19 = self::mul($g6_19, $f7, 25);
- $f7g7_38 = self::mul($g7_19, $f7_2, 26);
- $f7g8_19 = self::mul($g8_19, $f7, 25);
- $f7g9_38 = self::mul($g9_19,$f7_2, 26);
- $f8g0 = self::mul($f8, $g0, 26);
- $f8g1 = self::mul($f8, $g1, 25);
- $f8g2_19 = self::mul($g2_19, $f8, 26);
- $f8g3_19 = self::mul($g3_19, $f8, 26);
- $f8g4_19 = self::mul($g4_19, $f8, 26);
- $f8g5_19 = self::mul($g5_19, $f8, 26);
- $f8g6_19 = self::mul($g6_19, $f8, 26);
- $f8g7_19 = self::mul($g7_19, $f8, 26);
- $f8g8_19 = self::mul($g8_19, $f8, 26);
- $f8g9_19 = self::mul($g9_19, $f8, 26);
- $f9g0 = self::mul($f9, $g0, 26);
- $f9g1_38 = self::mul($g1_19, $f9_2, 26);
- $f9g2_19 = self::mul($g2_19, $f9, 25);
- $f9g3_38 = self::mul($g3_19, $f9_2, 26);
- $f9g4_19 = self::mul($g4_19, $f9, 25);
- $f9g5_38 = self::mul($g5_19, $f9_2, 26);
- $f9g6_19 = self::mul($g6_19, $f9, 25);
- $f9g7_38 = self::mul($g7_19, $f9_2, 26);
- $f9g8_19 = self::mul($g8_19, $f9, 25);
- $f9g9_38 = self::mul($g9_19, $f9_2, 26);
- $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
- $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
- $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
- $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
- $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
- $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
- $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38;
- $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19;
- $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38;
- $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
-
- /** @var int $carry1 */
- $carry1 = ($h1 + (1 << 24)) >> 25;
- $h2 += $carry1;
- $h1 -= $carry1 << 25;
- /** @var int $carry5 */
- $carry5 = ($h5 + (1 << 24)) >> 25;
- $h6 += $carry5;
- $h5 -= $carry5 << 25;
-
- /** @var int $carry2 */
- $carry2 = ($h2 + (1 << 25)) >> 26;
- $h3 += $carry2;
- $h2 -= $carry2 << 26;
- /** @var int $carry6 */
- $carry6 = ($h6 + (1 << 25)) >> 26;
- $h7 += $carry6;
- $h6 -= $carry6 << 26;
-
- /** @var int $carry3 */
- $carry3 = ($h3 + (1 << 24)) >> 25;
- $h4 += $carry3;
- $h3 -= $carry3 << 25;
- /** @var int $carry7 */
- $carry7 = ($h7 + (1 << 24)) >> 25;
- $h8 += $carry7;
- $h7 -= $carry7 << 25;
-
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
- /** @var int $carry8 */
- $carry8 = ($h8 + (1 << 25)) >> 26;
- $h9 += $carry8;
- $h8 -= $carry8 << 26;
-
- /** @var int $carry9 */
- $carry9 = ($h9 + (1 << 24)) >> 25;
- $h0 += self::mul($carry9, 19, 5);
- $h9 -= $carry9 << 25;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
-
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(
- (int) $h0,
- (int) $h1,
- (int) $h2,
- (int) $h3,
- (int) $h4,
- (int) $h5,
- (int) $h6,
- (int) $h7,
- (int) $h8,
- (int) $h9
- )
- );
- }
-
- /**
- * Get the negative values for each piece of the field element.
- *
- * h = -f
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- * @psalm-suppress MixedAssignment
- */
- public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- $h = new ParagonIE_Sodium_Core_Curve25519_Fe();
- for ($i = 0; $i < 10; ++$i) {
- $h[$i] = -$f[$i];
- }
- return $h;
- }
-
- /**
- * Square a field element
- *
- * h = f * f
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- $f0 = (int) $f[0];
- $f1 = (int) $f[1];
- $f2 = (int) $f[2];
- $f3 = (int) $f[3];
- $f4 = (int) $f[4];
- $f5 = (int) $f[5];
- $f6 = (int) $f[6];
- $f7 = (int) $f[7];
- $f8 = (int) $f[8];
- $f9 = (int) $f[9];
-
- /** @var int $f0_2 */
- $f0_2 = $f0 << 1;
- /** @var int $f1_2 */
- $f1_2 = $f1 << 1;
- /** @var int $f2_2 */
- $f2_2 = $f2 << 1;
- /** @var int $f3_2 */
- $f3_2 = $f3 << 1;
- /** @var int $f4_2 */
- $f4_2 = $f4 << 1;
- /** @var int $f5_2 */
- $f5_2 = $f5 << 1;
- /** @var int $f6_2 */
- $f6_2 = $f6 << 1;
- /** @var int $f7_2 */
- $f7_2 = $f7 << 1;
- $f5_38 = self::mul($f5, 38, 6);
- $f6_19 = self::mul($f6, 19, 5);
- $f7_38 = self::mul($f7, 38, 6);
- $f8_19 = self::mul($f8, 19, 5);
- $f9_38 = self::mul($f9, 38, 6);
- $f0f0 = self::mul($f0, $f0, 25);
- $f0f1_2 = self::mul($f0_2, $f1, 24);
- $f0f2_2 = self::mul($f0_2, $f2, 26);
- $f0f3_2 = self::mul($f0_2, $f3, 24);
- $f0f4_2 = self::mul($f0_2, $f4, 25);
- $f0f5_2 = self::mul($f0_2, $f5, 25);
- $f0f6_2 = self::mul($f0_2, $f6, 25);
- $f0f7_2 = self::mul($f0_2, $f7, 24);
- $f0f8_2 = self::mul($f0_2, $f8, 25);
- $f0f9_2 = self::mul($f0_2, $f9, 25);
- $f1f1_2 = self::mul($f1_2, $f1, 24);
- $f1f2_2 = self::mul($f1_2, $f2, 26);
- $f1f3_4 = self::mul($f1_2, $f3_2, 25);
- $f1f4_2 = self::mul($f1_2, $f4, 25);
- $f1f5_4 = self::mul($f1_2, $f5_2, 26);
- $f1f6_2 = self::mul($f1_2, $f6, 25);
- $f1f7_4 = self::mul($f1_2, $f7_2, 25);
- $f1f8_2 = self::mul($f1_2, $f8, 25);
- $f1f9_76 = self::mul($f9_38, $f1_2, 25);
- $f2f2 = self::mul($f2, $f2, 26);
- $f2f3_2 = self::mul($f2_2, $f3, 24);
- $f2f4_2 = self::mul($f2_2, $f4, 25);
- $f2f5_2 = self::mul($f2_2, $f5, 25);
- $f2f6_2 = self::mul($f2_2, $f6, 25);
- $f2f7_2 = self::mul($f2_2, $f7, 25);
- $f2f8_38 = self::mul($f8_19, $f2_2, 27);
- $f2f9_38 = self::mul($f9_38, $f2, 26);
- $f3f3_2 = self::mul($f3_2, $f3, 25);
- $f3f4_2 = self::mul($f3_2, $f4, 25);
- $f3f5_4 = self::mul($f3_2, $f5_2, 26);
- $f3f6_2 = self::mul($f3_2, $f6, 25);
- $f3f7_76 = self::mul($f7_38, $f3_2, 25);
- $f3f8_38 = self::mul($f8_19, $f3_2, 25);
- $f3f9_76 = self::mul($f9_38, $f3_2, 25);
- $f4f4 = self::mul($f4, $f4, 25);
- $f4f5_2 = self::mul($f4_2, $f5, 25);
- $f4f6_38 = self::mul($f6_19, $f4_2, 26);
- $f4f7_38 = self::mul($f7_38, $f4, 25);
- $f4f8_38 = self::mul($f8_19, $f4_2, 26);
- $f4f9_38 = self::mul($f9_38, $f4, 25);
- $f5f5_38 = self::mul($f5_38, $f5, 25);
- $f5f6_38 = self::mul($f6_19, $f5_2, 26);
- $f5f7_76 = self::mul($f7_38, $f5_2, 26);
- $f5f8_38 = self::mul($f8_19, $f5_2, 26);
- $f5f9_76 = self::mul($f9_38, $f5_2, 26);
- $f6f6_19 = self::mul($f6_19, $f6, 25);
- $f6f7_38 = self::mul($f7_38, $f6, 25);
- $f6f8_38 = self::mul($f8_19, $f6_2, 26);
- $f6f9_38 = self::mul($f9_38, $f6, 25);
- $f7f7_38 = self::mul($f7_38, $f7, 24);
- $f7f8_38 = self::mul($f8_19, $f7_2, 25);
- $f7f9_76 = self::mul($f9_38, $f7_2, 25);
- $f8f8_19 = self::mul($f8_19, $f8, 25);
- $f8f9_38 = self::mul($f9_38, $f8, 25);
- $f9f9_38 = self::mul($f9_38, $f9, 25);
- $h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38;
- $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
- $h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19;
- $h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38;
- $h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38;
- $h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38;
- $h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19;
- $h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38;
- $h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38;
- $h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
-
- /** @var int $carry1 */
- $carry1 = ($h1 + (1 << 24)) >> 25;
- $h2 += $carry1;
- $h1 -= $carry1 << 25;
- /** @var int $carry5 */
- $carry5 = ($h5 + (1 << 24)) >> 25;
- $h6 += $carry5;
- $h5 -= $carry5 << 25;
-
- /** @var int $carry2 */
- $carry2 = ($h2 + (1 << 25)) >> 26;
- $h3 += $carry2;
- $h2 -= $carry2 << 26;
- /** @var int $carry6 */
- $carry6 = ($h6 + (1 << 25)) >> 26;
- $h7 += $carry6;
- $h6 -= $carry6 << 26;
-
- /** @var int $carry3 */
- $carry3 = ($h3 + (1 << 24)) >> 25;
- $h4 += $carry3;
- $h3 -= $carry3 << 25;
- /** @var int $carry7 */
- $carry7 = ($h7 + (1 << 24)) >> 25;
- $h8 += $carry7;
- $h7 -= $carry7 << 25;
-
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
- /** @var int $carry8 */
- $carry8 = ($h8 + (1 << 25)) >> 26;
- $h9 += $carry8;
- $h8 -= $carry8 << 26;
-
- /** @var int $carry9 */
- $carry9 = ($h9 + (1 << 24)) >> 25;
- $h0 += self::mul($carry9, 19, 5);
- $h9 -= $carry9 << 25;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
-
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(
- (int) $h0,
- (int) $h1,
- (int) $h2,
- (int) $h3,
- (int) $h4,
- (int) $h5,
- (int) $h6,
- (int) $h7,
- (int) $h8,
- (int) $h9
- )
- );
- }
-
-
- /**
- * Square and double a field element
- *
- * h = 2 * f * f
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- $f0 = (int) $f[0];
- $f1 = (int) $f[1];
- $f2 = (int) $f[2];
- $f3 = (int) $f[3];
- $f4 = (int) $f[4];
- $f5 = (int) $f[5];
- $f6 = (int) $f[6];
- $f7 = (int) $f[7];
- $f8 = (int) $f[8];
- $f9 = (int) $f[9];
-
- /** @var int $f0_2 */
- $f0_2 = $f0 << 1;
- /** @var int $f1_2 */
- $f1_2 = $f1 << 1;
- /** @var int $f2_2 */
- $f2_2 = $f2 << 1;
- /** @var int $f3_2 */
- $f3_2 = $f3 << 1;
- /** @var int $f4_2 */
- $f4_2 = $f4 << 1;
- /** @var int $f5_2 */
- $f5_2 = $f5 << 1;
- /** @var int $f6_2 */
- $f6_2 = $f6 << 1;
- /** @var int $f7_2 */
- $f7_2 = $f7 << 1;
- $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
- $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
- $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
- $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
- $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
- $f0f0 = self::mul($f0, $f0, 24);
- $f0f1_2 = self::mul($f0_2, $f1, 24);
- $f0f2_2 = self::mul($f0_2, $f2, 24);
- $f0f3_2 = self::mul($f0_2, $f3, 24);
- $f0f4_2 = self::mul($f0_2, $f4, 24);
- $f0f5_2 = self::mul($f0_2, $f5, 24);
- $f0f6_2 = self::mul($f0_2, $f6, 24);
- $f0f7_2 = self::mul($f0_2, $f7, 24);
- $f0f8_2 = self::mul($f0_2, $f8, 24);
- $f0f9_2 = self::mul($f0_2, $f9, 24);
- $f1f1_2 = self::mul($f1_2, $f1, 24);
- $f1f2_2 = self::mul($f1_2, $f2, 24);
- $f1f3_4 = self::mul($f1_2, $f3_2, 24);
- $f1f4_2 = self::mul($f1_2, $f4, 24);
- $f1f5_4 = self::mul($f1_2, $f5_2, 24);
- $f1f6_2 = self::mul($f1_2, $f6, 24);
- $f1f7_4 = self::mul($f1_2, $f7_2, 24);
- $f1f8_2 = self::mul($f1_2, $f8, 24);
- $f1f9_76 = self::mul($f9_38, $f1_2, 24);
- $f2f2 = self::mul($f2, $f2, 24);
- $f2f3_2 = self::mul($f2_2, $f3, 24);
- $f2f4_2 = self::mul($f2_2, $f4, 24);
- $f2f5_2 = self::mul($f2_2, $f5, 24);
- $f2f6_2 = self::mul($f2_2, $f6, 24);
- $f2f7_2 = self::mul($f2_2, $f7, 24);
- $f2f8_38 = self::mul($f8_19, $f2_2, 25);
- $f2f9_38 = self::mul($f9_38, $f2, 24);
- $f3f3_2 = self::mul($f3_2, $f3, 24);
- $f3f4_2 = self::mul($f3_2, $f4, 24);
- $f3f5_4 = self::mul($f3_2, $f5_2, 24);
- $f3f6_2 = self::mul($f3_2, $f6, 24);
- $f3f7_76 = self::mul($f7_38, $f3_2, 24);
- $f3f8_38 = self::mul($f8_19, $f3_2, 24);
- $f3f9_76 = self::mul($f9_38, $f3_2, 24);
- $f4f4 = self::mul($f4, $f4, 24);
- $f4f5_2 = self::mul($f4_2, $f5, 24);
- $f4f6_38 = self::mul($f6_19, $f4_2, 25);
- $f4f7_38 = self::mul($f7_38, $f4, 24);
- $f4f8_38 = self::mul($f8_19, $f4_2, 25);
- $f4f9_38 = self::mul($f9_38, $f4, 24);
- $f5f5_38 = self::mul($f5_38, $f5, 24);
- $f5f6_38 = self::mul($f6_19, $f5_2, 24);
- $f5f7_76 = self::mul($f7_38, $f5_2, 24);
- $f5f8_38 = self::mul($f8_19, $f5_2, 24);
- $f5f9_76 = self::mul($f9_38, $f5_2, 24);
- $f6f6_19 = self::mul($f6_19, $f6, 24);
- $f6f7_38 = self::mul($f7_38, $f6, 24);
- $f6f8_38 = self::mul($f8_19, $f6_2, 25);
- $f6f9_38 = self::mul($f9_38, $f6, 24);
- $f7f7_38 = self::mul($f7_38, $f7, 24);
- $f7f8_38 = self::mul($f8_19, $f7_2, 24);
- $f7f9_76 = self::mul($f9_38, $f7_2, 24);
- $f8f8_19 = self::mul($f8_19, $f8, 24);
- $f8f9_38 = self::mul($f9_38, $f8, 24);
- $f9f9_38 = self::mul($f9_38, $f9, 24);
-
- /** @var int $h0 */
- $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1;
- /** @var int $h1 */
- $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1;
- /** @var int $h2 */
- $h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1;
- /** @var int $h3 */
- $h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1;
- /** @var int $h4 */
- $h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1;
- /** @var int $h5 */
- $h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38) << 1;
- /** @var int $h6 */
- $h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19) << 1;
- /** @var int $h7 */
- $h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38) << 1;
- /** @var int $h8 */
- $h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38) << 1;
- /** @var int $h9 */
- $h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2) << 1;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
-
- /** @var int $carry1 */
- $carry1 = ($h1 + (1 << 24)) >> 25;
- $h2 += $carry1;
- $h1 -= $carry1 << 25;
- /** @var int $carry5 */
- $carry5 = ($h5 + (1 << 24)) >> 25;
- $h6 += $carry5;
- $h5 -= $carry5 << 25;
-
- /** @var int $carry2 */
- $carry2 = ($h2 + (1 << 25)) >> 26;
- $h3 += $carry2;
- $h2 -= $carry2 << 26;
- /** @var int $carry6 */
- $carry6 = ($h6 + (1 << 25)) >> 26;
- $h7 += $carry6;
- $h6 -= $carry6 << 26;
-
- /** @var int $carry3 */
- $carry3 = ($h3 + (1 << 24)) >> 25;
- $h4 += $carry3;
- $h3 -= $carry3 << 25;
- /** @var int $carry7 */
- $carry7 = ($h7 + (1 << 24)) >> 25;
- $h8 += $carry7;
- $h7 -= $carry7 << 25;
-
- /** @var int $carry4 */
- $carry4 = ($h4 + (1 << 25)) >> 26;
- $h5 += $carry4;
- $h4 -= $carry4 << 26;
- /** @var int $carry8 */
- $carry8 = ($h8 + (1 << 25)) >> 26;
- $h9 += $carry8;
- $h8 -= $carry8 << 26;
-
- /** @var int $carry9 */
- $carry9 = ($h9 + (1 << 24)) >> 25;
- $h0 += self::mul($carry9, 19, 5);
- $h9 -= $carry9 << 25;
-
- /** @var int $carry0 */
- $carry0 = ($h0 + (1 << 25)) >> 26;
- $h1 += $carry0;
- $h0 -= $carry0 << 26;
-
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(
- (int) $h0,
- (int) $h1,
- (int) $h2,
- (int) $h3,
- (int) $h4,
- (int) $h5,
- (int) $h6,
- (int) $h7,
- (int) $h8,
- (int) $h9
- )
- );
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z)
- {
- $z = clone $Z;
- $t0 = self::fe_sq($z);
- $t1 = self::fe_sq($t0);
- $t1 = self::fe_sq($t1);
- $t1 = self::fe_mul($z, $t1);
- $t0 = self::fe_mul($t0, $t1);
- $t2 = self::fe_sq($t0);
- $t1 = self::fe_mul($t1, $t2);
- $t2 = self::fe_sq($t1);
- for ($i = 1; $i < 5; ++$i) {
- $t2 = self::fe_sq($t2);
- }
- $t1 = self::fe_mul($t2, $t1);
- $t2 = self::fe_sq($t1);
- for ($i = 1; $i < 10; ++$i) {
- $t2 = self::fe_sq($t2);
- }
- $t2 = self::fe_mul($t2, $t1);
- $t3 = self::fe_sq($t2);
- for ($i = 1; $i < 20; ++$i) {
- $t3 = self::fe_sq($t3);
- }
- $t2 = self::fe_mul($t3, $t2);
- $t2 = self::fe_sq($t2);
- for ($i = 1; $i < 10; ++$i) {
- $t2 = self::fe_sq($t2);
- }
- $t1 = self::fe_mul($t2, $t1);
- $t2 = self::fe_sq($t1);
- for ($i = 1; $i < 50; ++$i) {
- $t2 = self::fe_sq($t2);
- }
- $t2 = self::fe_mul($t2, $t1);
- $t3 = self::fe_sq($t2);
- for ($i = 1; $i < 100; ++$i) {
- $t3 = self::fe_sq($t3);
- }
- $t2 = self::fe_mul($t3, $t2);
- $t2 = self::fe_sq($t2);
- for ($i = 1; $i < 50; ++$i) {
- $t2 = self::fe_sq($t2);
- }
- $t1 = self::fe_mul($t2, $t1);
- $t1 = self::fe_sq($t1);
- for ($i = 1; $i < 5; ++$i) {
- $t1 = self::fe_sq($t1);
- }
- return self::fe_mul($t1, $t0);
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $z
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z)
- {
- # fe_sq(t0, z);
- # fe_sq(t1, t0);
- # fe_sq(t1, t1);
- # fe_mul(t1, z, t1);
- # fe_mul(t0, t0, t1);
- # fe_sq(t0, t0);
- # fe_mul(t0, t1, t0);
- # fe_sq(t1, t0);
- $t0 = self::fe_sq($z);
- $t1 = self::fe_sq($t0);
- $t1 = self::fe_sq($t1);
- $t1 = self::fe_mul($z, $t1);
- $t0 = self::fe_mul($t0, $t1);
- $t0 = self::fe_sq($t0);
- $t0 = self::fe_mul($t1, $t0);
- $t1 = self::fe_sq($t0);
-
- # for (i = 1; i < 5; ++i) {
- # fe_sq(t1, t1);
- # }
- for ($i = 1; $i < 5; ++$i) {
- $t1 = self::fe_sq($t1);
- }
-
- # fe_mul(t0, t1, t0);
- # fe_sq(t1, t0);
- $t0 = self::fe_mul($t1, $t0);
- $t1 = self::fe_sq($t0);
-
- # for (i = 1; i < 10; ++i) {
- # fe_sq(t1, t1);
- # }
- for ($i = 1; $i < 10; ++$i) {
- $t1 = self::fe_sq($t1);
- }
-
- # fe_mul(t1, t1, t0);
- # fe_sq(t2, t1);
- $t1 = self::fe_mul($t1, $t0);
- $t2 = self::fe_sq($t1);
-
- # for (i = 1; i < 20; ++i) {
- # fe_sq(t2, t2);
- # }
- for ($i = 1; $i < 20; ++$i) {
- $t2 = self::fe_sq($t2);
- }
-
- # fe_mul(t1, t2, t1);
- # fe_sq(t1, t1);
- $t1 = self::fe_mul($t2, $t1);
- $t1 = self::fe_sq($t1);
-
- # for (i = 1; i < 10; ++i) {
- # fe_sq(t1, t1);
- # }
- for ($i = 1; $i < 10; ++$i) {
- $t1 = self::fe_sq($t1);
- }
-
- # fe_mul(t0, t1, t0);
- # fe_sq(t1, t0);
- $t0 = self::fe_mul($t1, $t0);
- $t1 = self::fe_sq($t0);
-
- # for (i = 1; i < 50; ++i) {
- # fe_sq(t1, t1);
- # }
- for ($i = 1; $i < 50; ++$i) {
- $t1 = self::fe_sq($t1);
- }
-
- # fe_mul(t1, t1, t0);
- # fe_sq(t2, t1);
- $t1 = self::fe_mul($t1, $t0);
- $t2 = self::fe_sq($t1);
-
- # for (i = 1; i < 100; ++i) {
- # fe_sq(t2, t2);
- # }
- for ($i = 1; $i < 100; ++$i) {
- $t2 = self::fe_sq($t2);
- }
-
- # fe_mul(t1, t2, t1);
- # fe_sq(t1, t1);
- $t1 = self::fe_mul($t2, $t1);
- $t1 = self::fe_sq($t1);
-
- # for (i = 1; i < 50; ++i) {
- # fe_sq(t1, t1);
- # }
- for ($i = 1; $i < 50; ++$i) {
- $t1 = self::fe_sq($t1);
- }
-
- # fe_mul(t0, t1, t0);
- # fe_sq(t0, t0);
- # fe_sq(t0, t0);
- # fe_mul(out, t0, z);
- $t0 = self::fe_mul($t1, $t0);
- $t0 = self::fe_sq($t0);
- $t0 = self::fe_sq($t0);
- return self::fe_mul($t0, $z);
- }
-
- /**
- * Subtract two field elements.
- *
- * h = f - g
- *
- * Preconditions:
- * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
- * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
- *
- * Postconditions:
- * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- * @psalm-suppress MixedOperand
- */
- public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g)
- {
- return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
- array(
- (int) ($f[0] - $g[0]),
- (int) ($f[1] - $g[1]),
- (int) ($f[2] - $g[2]),
- (int) ($f[3] - $g[3]),
- (int) ($f[4] - $g[4]),
- (int) ($f[5] - $g[5]),
- (int) ($f[6] - $g[6]),
- (int) ($f[7] - $g[7]),
- (int) ($f[8] - $g[8]),
- (int) ($f[9] - $g[9])
- )
- );
- }
-
- /**
- * Add two group elements.
- *
- * r = p + q
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
- */
- public static function ge_add(
- ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
- ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
- ) {
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
- $r->X = self::fe_add($p->Y, $p->X);
- $r->Y = self::fe_sub($p->Y, $p->X);
- $r->Z = self::fe_mul($r->X, $q->YplusX);
- $r->Y = self::fe_mul($r->Y, $q->YminusX);
- $r->T = self::fe_mul($q->T2d, $p->T);
- $r->X = self::fe_mul($p->Z, $q->Z);
- $t0 = self::fe_add($r->X, $r->X);
- $r->X = self::fe_sub($r->Z, $r->Y);
- $r->Y = self::fe_add($r->Z, $r->Y);
- $r->Z = self::fe_add($t0, $r->T);
- $r->T = self::fe_sub($t0, $r->T);
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
- * @param string $a
- * @return array<int, mixed>
- * @throws SodiumException
- * @throws TypeError
- */
- public static function slide($a)
- {
- if (self::strlen($a) < 256) {
- if (self::strlen($a) < 16) {
- $a = str_pad($a, 256, '0', STR_PAD_RIGHT);
- }
- }
- /** @var array<int, int> $r */
- $r = array();
-
- /** @var int $i */
- for ($i = 0; $i < 256; ++$i) {
- $r[$i] = (int) (
- 1 & (
- self::chrToInt($a[(int) ($i >> 3)])
- >>
- ($i & 7)
- )
- );
- }
-
- for ($i = 0;$i < 256;++$i) {
- if ($r[$i]) {
- for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
- if ($r[$i + $b]) {
- if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
- $r[$i] += $r[$i + $b] << $b;
- $r[$i + $b] = 0;
- } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
- $r[$i] -= $r[$i + $b] << $b;
- for ($k = $i + $b; $k < 256; ++$k) {
- if (!$r[$k]) {
- $r[$k] = 1;
- break;
- }
- $r[$k] = 0;
- }
- } else {
- break;
- }
- }
- }
- }
- }
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param string $s
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
- * @throws SodiumException
- * @throws TypeError
- */
- public static function ge_frombytes_negate_vartime($s)
- {
- static $d = null;
- if (!$d) {
- $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
- }
-
- # fe_frombytes(h->Y,s);
- # fe_1(h->Z);
- $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
- self::fe_0(),
- self::fe_frombytes($s),
- self::fe_1()
- );
-
- # fe_sq(u,h->Y);
- # fe_mul(v,u,d);
- # fe_sub(u,u,h->Z); /* u = y^2-1 */
- # fe_add(v,v,h->Z); /* v = dy^2+1 */
- $u = self::fe_sq($h->Y);
- /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
- $v = self::fe_mul($u, $d);
- $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */
- $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
-
- # fe_sq(v3,v);
- # fe_mul(v3,v3,v); /* v3 = v^3 */
- # fe_sq(h->X,v3);
- # fe_mul(h->X,h->X,v);
- # fe_mul(h->X,h->X,u); /* x = uv^7 */
- $v3 = self::fe_sq($v);
- $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
- $h->X = self::fe_sq($v3);
- $h->X = self::fe_mul($h->X, $v);
- $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
-
- # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
- # fe_mul(h->X,h->X,v3);
- # fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
- $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
- $h->X = self::fe_mul($h->X, $v3);
- $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
-
- # fe_sq(vxx,h->X);
- # fe_mul(vxx,vxx,v);
- # fe_sub(check,vxx,u); /* vx^2-u */
- $vxx = self::fe_sq($h->X);
- $vxx = self::fe_mul($vxx, $v);
- $check = self::fe_sub($vxx, $u); /* vx^2 - u */
-
- # if (fe_isnonzero(check)) {
- # fe_add(check,vxx,u); /* vx^2+u */
- # if (fe_isnonzero(check)) {
- # return -1;
- # }
- # fe_mul(h->X,h->X,sqrtm1);
- # }
- if (self::fe_isnonzero($check)) {
- $check = self::fe_add($vxx, $u); /* vx^2 + u */
- if (self::fe_isnonzero($check)) {
- throw new RangeException('Internal check failed.');
- }
- $h->X = self::fe_mul(
- $h->X,
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
- );
- }
-
- # if (fe_isnegative(h->X) == (s[31] >> 7)) {
- # fe_neg(h->X,h->X);
- # }
- $i = self::chrToInt($s[31]);
- if (self::fe_isnegative($h->X) === ($i >> 7)) {
- $h->X = self::fe_neg($h->X);
- }
-
- # fe_mul(h->T,h->X,h->Y);
- $h->T = self::fe_mul($h->X, $h->Y);
- return $h;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
- */
- public static function ge_madd(
- ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
- ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
- ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
- ) {
- $r = clone $R;
- $r->X = self::fe_add($p->Y, $p->X);
- $r->Y = self::fe_sub($p->Y, $p->X);
- $r->Z = self::fe_mul($r->X, $q->yplusx);
- $r->Y = self::fe_mul($r->Y, $q->yminusx);
- $r->T = self::fe_mul($q->xy2d, $p->T);
- $t0 = self::fe_add(clone $p->Z, clone $p->Z);
- $r->X = self::fe_sub($r->Z, $r->Y);
- $r->Y = self::fe_add($r->Z, $r->Y);
- $r->Z = self::fe_add($t0, $r->T);
- $r->T = self::fe_sub($t0, $r->T);
-
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
- */
- public static function ge_msub(
- ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
- ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
- ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
- ) {
- $r = clone $R;
-
- $r->X = self::fe_add($p->Y, $p->X);
- $r->Y = self::fe_sub($p->Y, $p->X);
- $r->Z = self::fe_mul($r->X, $q->yminusx);
- $r->Y = self::fe_mul($r->Y, $q->yplusx);
- $r->T = self::fe_mul($q->xy2d, $p->T);
- $t0 = self::fe_add($p->Z, $p->Z);
- $r->X = self::fe_sub($r->Z, $r->Y);
- $r->Y = self::fe_add($r->Z, $r->Y);
- $r->Z = self::fe_sub($t0, $r->T);
- $r->T = self::fe_add($t0, $r->T);
-
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
- */
- public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
- {
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
- $r->X = self::fe_mul($p->X, $p->T);
- $r->Y = self::fe_mul($p->Y, $p->Z);
- $r->Z = self::fe_mul($p->Z, $p->T);
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
- */
- public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
- {
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
- $r->X = self::fe_mul($p->X, $p->T);
- $r->Y = self::fe_mul($p->Y, $p->Z);
- $r->Z = self::fe_mul($p->Z, $p->T);
- $r->T = self::fe_mul($p->X, $p->Y);
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
- */
- public static function ge_p2_0()
- {
- return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
- self::fe_0(),
- self::fe_1(),
- self::fe_1()
- );
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
- */
- public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p)
- {
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
-
- $r->X = self::fe_sq($p->X);
- $r->Z = self::fe_sq($p->Y);
- $r->T = self::fe_sq2($p->Z);
- $r->Y = self::fe_add($p->X, $p->Y);
- $t0 = self::fe_sq($r->Y);
- $r->Y = self::fe_add($r->Z, $r->X);
- $r->Z = self::fe_sub($r->Z, $r->X);
- $r->X = self::fe_sub($t0, $r->Y);
- $r->T = self::fe_sub($r->T, $r->Z);
-
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
- */
- public static function ge_p3_0()
- {
- return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
- self::fe_0(),
- self::fe_1(),
- self::fe_1(),
- self::fe_0()
- );
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
- */
- public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
- {
- static $d2 = null;
- if ($d2 === null) {
- $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
- }
- /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
- $r->YplusX = self::fe_add($p->Y, $p->X);
- $r->YminusX = self::fe_sub($p->Y, $p->X);
- $r->Z = self::fe_copy($p->Z);
- $r->T2d = self::fe_mul($p->T, $d2);
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
- */
- public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
- {
- return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
- self::fe_copy($p->X),
- self::fe_copy($p->Y),
- self::fe_copy($p->Z)
- );
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
- {
- $recip = self::fe_invert($h->Z);
- $x = self::fe_mul($h->X, $recip);
- $y = self::fe_mul($h->Y, $recip);
- $s = self::fe_tobytes($y);
- $s[31] = self::intToChr(
- self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
- );
- return $s;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
- */
- public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
- {
- $q = self::ge_p3_to_p2($p);
- return self::ge_p2_dbl($q);
- }
-
- /**
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
- */
- public static function ge_precomp_0()
- {
- return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
- self::fe_1(),
- self::fe_1(),
- self::fe_0()
- );
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param int $b
- * @param int $c
- * @return int
- */
- public static function equal($b, $c)
- {
- return (int) ((($b ^ $c) - 1) >> 31) & 1;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param int|string $char
- * @return int (1 = yes, 0 = no)
- * @throws SodiumException
- * @throws TypeError
- */
- public static function negative($char)
- {
- if (is_int($char)) {
- return ($char >> 63) & 1;
- }
- $x = self::chrToInt(self::substr($char, 0, 1));
- return (int) ($x >> 63);
- }
-
- /**
- * Conditional move
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
- * @param int $b
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
- */
- public static function cmov(
- ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
- ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
- $b
- ) {
- if (!is_int($b)) {
- throw new InvalidArgumentException('Expected an integer.');
- }
- return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
- self::fe_cmov($t->yplusx, $u->yplusx, $b),
- self::fe_cmov($t->yminusx, $u->yminusx, $b),
- self::fe_cmov($t->xy2d, $u->xy2d, $b)
- );
- }
-
- /**
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u
- * @param int $b
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
- */
- public static function ge_cmov_cached(
- ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t,
- ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u,
- $b
- ) {
- $b &= 1;
- $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
- $ret->YplusX = self::fe_cmov($t->YplusX, $u->YplusX, $b);
- $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b);
- $ret->Z = self::fe_cmov($t->Z, $u->Z, $b);
- $ret->T2d = self::fe_cmov($t->T2d, $u->T2d, $b);
- return $ret;
- }
-
- /**
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached
- * @param int $b
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
- * @throws SodiumException
- */
- public static function ge_cmov8_cached(array $cached, $b)
- {
- // const unsigned char bnegative = negative(b);
- // const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1));
- $bnegative = self::negative($b);
- $babs = $b - (((-$bnegative) & $b) << 1);
-
- // ge25519_cached_0(t);
- $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
- self::fe_1(),
- self::fe_1(),
- self::fe_1(),
- self::fe_0()
- );
-
- // ge25519_cmov_cached(t, &cached[0], equal(babs, 1));
- // ge25519_cmov_cached(t, &cached[1], equal(babs, 2));
- // ge25519_cmov_cached(t, &cached[2], equal(babs, 3));
- // ge25519_cmov_cached(t, &cached[3], equal(babs, 4));
- // ge25519_cmov_cached(t, &cached[4], equal(babs, 5));
- // ge25519_cmov_cached(t, &cached[5], equal(babs, 6));
- // ge25519_cmov_cached(t, &cached[6], equal(babs, 7));
- // ge25519_cmov_cached(t, &cached[7], equal(babs, 8));
- for ($x = 0; $x < 8; ++$x) {
- $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1));
- }
-
- // fe25519_copy(minust.YplusX, t->YminusX);
- // fe25519_copy(minust.YminusX, t->YplusX);
- // fe25519_copy(minust.Z, t->Z);
- // fe25519_neg(minust.T2d, t->T2d);
- $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
- self::fe_copy($t->YminusX),
- self::fe_copy($t->YplusX),
- self::fe_copy($t->Z),
- self::fe_neg($t->T2d)
- );
- return self::ge_cmov_cached($t, $minust, $bnegative);
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param int $pos
- * @param int $b
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
- * @throws SodiumException
- * @throws TypeError
- * @psalm-suppress MixedArgument
- * @psalm-suppress MixedArrayAccess
- * @psalm-suppress MixedArrayOffset
- */
- public static function ge_select($pos = 0, $b = 0)
- {
- static $base = null;
- if ($base === null) {
- $base = array();
- /** @var int $i */
- foreach (self::$base as $i => $bas) {
- for ($j = 0; $j < 8; ++$j) {
- $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
- );
- }
- }
- }
- /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
- if (!is_int($pos)) {
- throw new InvalidArgumentException('Position must be an integer');
- }
- if ($pos < 0 || $pos > 31) {
- throw new RangeException('Position is out of range [0, 31]');
- }
-
- /** @var int $bnegative */
- $bnegative = self::negative($b);
- /** @var int $babs */
- $babs = $b - (((-$bnegative) & $b) << 1);
-
- $t = self::ge_precomp_0();
- for ($i = 0; $i < 8; ++$i) {
- $t = self::cmov(
- $t,
- $base[$pos][$i],
- self::equal($babs, $i + 1)
- );
- }
- $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
- self::fe_copy($t->yminusx),
- self::fe_copy($t->yplusx),
- self::fe_neg($t->xy2d)
- );
- return self::cmov($t, $minusT, $bnegative);
- }
-
- /**
- * Subtract two group elements.
- *
- * r = p - q
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
- */
- public static function ge_sub(
- ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
- ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
- ) {
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
-
- $r->X = self::fe_add($p->Y, $p->X);
- $r->Y = self::fe_sub($p->Y, $p->X);
- $r->Z = self::fe_mul($r->X, $q->YminusX);
- $r->Y = self::fe_mul($r->Y, $q->YplusX);
- $r->T = self::fe_mul($q->T2d, $p->T);
- $r->X = self::fe_mul($p->Z, $q->Z);
- $t0 = self::fe_add($r->X, $r->X);
- $r->X = self::fe_sub($r->Z, $r->Y);
- $r->Y = self::fe_add($r->Z, $r->Y);
- $r->Z = self::fe_sub($t0, $r->T);
- $r->T = self::fe_add($t0, $r->T);
-
- return $r;
- }
-
- /**
- * Convert a group element to a byte string.
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
- {
- $recip = self::fe_invert($h->Z);
- $x = self::fe_mul($h->X, $recip);
- $y = self::fe_mul($h->Y, $recip);
- $s = self::fe_tobytes($y);
- $s[31] = self::intToChr(
- self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
- );
- return $s;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param string $a
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
- * @param string $b
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
- * @throws SodiumException
- * @throws TypeError
- * @psalm-suppress MixedArgument
- * @psalm-suppress MixedArrayAccess
- */
- public static function ge_double_scalarmult_vartime(
- $a,
- ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
- $b
- ) {
- /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
- $Ai = array();
-
- /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
- static $Bi = array();
- if (!$Bi) {
- for ($i = 0; $i < 8; ++$i) {
- $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
- ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
- );
- }
- }
- for ($i = 0; $i < 8; ++$i) {
- $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
- self::fe_0(),
- self::fe_0(),
- self::fe_0(),
- self::fe_0()
- );
- }
-
- # slide(aslide,a);
- # slide(bslide,b);
- /** @var array<int, int> $aslide */
- $aslide = self::slide($a);
- /** @var array<int, int> $bslide */
- $bslide = self::slide($b);
-
- # ge_p3_to_cached(&Ai[0],A);
- # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
- $Ai[0] = self::ge_p3_to_cached($A);
- $t = self::ge_p3_dbl($A);
- $A2 = self::ge_p1p1_to_p3($t);
-
- # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
- # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
- # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
- # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
- # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
- # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
- # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
- for ($i = 0; $i < 7; ++$i) {
- $t = self::ge_add($A2, $Ai[$i]);
- $u = self::ge_p1p1_to_p3($t);
- $Ai[$i + 1] = self::ge_p3_to_cached($u);
- }
-
- # ge_p2_0(r);
- $r = self::ge_p2_0();
-
- # for (i = 255;i >= 0;--i) {
- # if (aslide[i] || bslide[i]) break;
- # }
- $i = 255;
- for (; $i >= 0; --$i) {
- if ($aslide[$i] || $bslide[$i]) {
- break;
- }
- }
-
- # for (;i >= 0;--i) {
- for (; $i >= 0; --$i) {
- # ge_p2_dbl(&t,r);
- $t = self::ge_p2_dbl($r);
-
- # if (aslide[i] > 0) {
- if ($aslide[$i] > 0) {
- # ge_p1p1_to_p3(&u,&t);
- # ge_add(&t,&u,&Ai[aslide[i]/2]);
- $u = self::ge_p1p1_to_p3($t);
- $t = self::ge_add(
- $u,
- $Ai[(int) floor($aslide[$i] / 2)]
- );
- # } else if (aslide[i] < 0) {
- } elseif ($aslide[$i] < 0) {
- # ge_p1p1_to_p3(&u,&t);
- # ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
- $u = self::ge_p1p1_to_p3($t);
- $t = self::ge_sub(
- $u,
- $Ai[(int) floor(-$aslide[$i] / 2)]
- );
- }
-
- # if (bslide[i] > 0) {
- if ($bslide[$i] > 0) {
- /** @var int $index */
- $index = (int) floor($bslide[$i] / 2);
- # ge_p1p1_to_p3(&u,&t);
- # ge_madd(&t,&u,&Bi[bslide[i]/2]);
- $u = self::ge_p1p1_to_p3($t);
- $t = self::ge_madd($t, $u, $Bi[$index]);
- # } else if (bslide[i] < 0) {
- } elseif ($bslide[$i] < 0) {
- /** @var int $index */
- $index = (int) floor(-$bslide[$i] / 2);
- # ge_p1p1_to_p3(&u,&t);
- # ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
- $u = self::ge_p1p1_to_p3($t);
- $t = self::ge_msub($t, $u, $Bi[$index]);
- }
- # ge_p1p1_to_p2(r,&t);
- $r = self::ge_p1p1_to_p2($t);
- }
- return $r;
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param string $a
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
- * @throws SodiumException
- * @throws TypeError
- * @psalm-suppress MixedAssignment
- * @psalm-suppress MixedOperand
- */
- public static function ge_scalarmult($a, $p)
- {
- $e = array_fill(0, 64, 0);
-
- /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */
- $pi = array();
-
- // ge25519_p3_to_cached(&pi[1 - 1], p); /* p */
- $pi[0] = self::ge_p3_to_cached($p);
-
- // ge25519_p3_dbl(&t2, p);
- // ge25519_p1p1_to_p3(&p2, &t2);
- // ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */
- $t2 = self::ge_p3_dbl($p);
- $p2 = self::ge_p1p1_to_p3($t2);
- $pi[1] = self::ge_p3_to_cached($p2);
-
- // ge25519_add_cached(&t3, p, &pi[2 - 1]);
- // ge25519_p1p1_to_p3(&p3, &t3);
- // ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */
- $t3 = self::ge_add($p, $pi[1]);
- $p3 = self::ge_p1p1_to_p3($t3);
- $pi[2] = self::ge_p3_to_cached($p3);
-
- // ge25519_p3_dbl(&t4, &p2);
- // ge25519_p1p1_to_p3(&p4, &t4);
- // ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */
- $t4 = self::ge_p3_dbl($p2);
- $p4 = self::ge_p1p1_to_p3($t4);
- $pi[3] = self::ge_p3_to_cached($p4);
-
- // ge25519_add_cached(&t5, p, &pi[4 - 1]);
- // ge25519_p1p1_to_p3(&p5, &t5);
- // ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */
- $t5 = self::ge_add($p, $pi[3]);
- $p5 = self::ge_p1p1_to_p3($t5);
- $pi[4] = self::ge_p3_to_cached($p5);
-
- // ge25519_p3_dbl(&t6, &p3);
- // ge25519_p1p1_to_p3(&p6, &t6);
- // ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */
- $t6 = self::ge_p3_dbl($p3);
- $p6 = self::ge_p1p1_to_p3($t6);
- $pi[5] = self::ge_p3_to_cached($p6);
-
- // ge25519_add_cached(&t7, p, &pi[6 - 1]);
- // ge25519_p1p1_to_p3(&p7, &t7);
- // ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */
- $t7 = self::ge_add($p, $pi[5]);
- $p7 = self::ge_p1p1_to_p3($t7);
- $pi[6] = self::ge_p3_to_cached($p7);
-
- // ge25519_p3_dbl(&t8, &p4);
- // ge25519_p1p1_to_p3(&p8, &t8);
- // ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */
- $t8 = self::ge_p3_dbl($p4);
- $p8 = self::ge_p1p1_to_p3($t8);
- $pi[7] = self::ge_p3_to_cached($p8);
-
-
- // for (i = 0; i < 32; ++i) {
- // e[2 * i + 0] = (a[i] >> 0) & 15;
- // e[2 * i + 1] = (a[i] >> 4) & 15;
- // }
- for ($i = 0; $i < 32; ++$i) {
- $e[($i << 1) ] = self::chrToInt($a[$i]) & 15;
- $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15;
- }
- // /* each e[i] is between 0 and 15 */
- // /* e[63] is between 0 and 7 */
-
- // carry = 0;
- // for (i = 0; i < 63; ++i) {
- // e[i] += carry;
- // carry = e[i] + 8;
- // carry >>= 4;
- // e[i] -= carry * ((signed char) 1 << 4);
- // }
- $carry = 0;
- for ($i = 0; $i < 64; ++$i) {
- $e[$i] += $carry;
- $carry = $e[$i] + 8;
- $carry >>= 4;
- $e[$i] -= $carry << 4;
- }
- // e[63] += carry;
- // /* each e[i] is between -8 and 8 */
- $e[63] += $carry;
-
- // ge25519_p3_0(h);
- $h = self::ge_p3_0();
-
- // for (i = 63; i != 0; i--) {
- for ($i = 63; $i != 0; --$i) {
- // ge25519_cmov8_cached(&t, pi, e[i]);
- $t = self::ge_cmov8_cached($pi, $e[$i]);
- // ge25519_add_cached(&r, h, &t);
- $r = self::ge_add($h, $t);
-
- // ge25519_p1p1_to_p2(&s, &r);
- // ge25519_p2_dbl(&r, &s);
- // ge25519_p1p1_to_p2(&s, &r);
- // ge25519_p2_dbl(&r, &s);
- // ge25519_p1p1_to_p2(&s, &r);
- // ge25519_p2_dbl(&r, &s);
- // ge25519_p1p1_to_p2(&s, &r);
- // ge25519_p2_dbl(&r, &s);
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
-
- // ge25519_p1p1_to_p3(h, &r); /* *16 */
- $h = self::ge_p1p1_to_p3($r); /* *16 */
- }
-
- // ge25519_cmov8_cached(&t, pi, e[i]);
- // ge25519_add_cached(&r, h, &t);
- // ge25519_p1p1_to_p3(h, &r);
- $t = self::ge_cmov8_cached($pi, $e[0]);
- $r = self::ge_add($h, $t);
- return self::ge_p1p1_to_p3($r);
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param string $a
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
- * @throws SodiumException
- * @throws TypeError
- * @psalm-suppress MixedAssignment
- * @psalm-suppress MixedOperand
- */
- public static function ge_scalarmult_base($a)
- {
- /** @var array<int, int> $e */
- $e = array();
- $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
-
- for ($i = 0; $i < 32; ++$i) {
- /** @var int $dbl */
- $dbl = (int) $i << 1;
- $e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
- $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
- }
-
- /** @var int $carry */
- $carry = 0;
- for ($i = 0; $i < 63; ++$i) {
- $e[$i] += $carry;
- /** @var int $carry */
- $carry = $e[$i] + 8;
- /** @var int $carry */
- $carry >>= 4;
- $e[$i] -= $carry << 4;
- }
- /** @var array<int, int> $e */
- $e[63] += (int) $carry;
-
- $h = self::ge_p3_0();
-
- for ($i = 1; $i < 64; $i += 2) {
- $t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
- $r = self::ge_madd($r, $h, $t);
- $h = self::ge_p1p1_to_p3($r);
- }
-
- $r = self::ge_p3_dbl($h);
-
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
- $s = self::ge_p1p1_to_p2($r);
- $r = self::ge_p2_dbl($s);
-
- $h = self::ge_p1p1_to_p3($r);
-
- for ($i = 0; $i < 64; $i += 2) {
- $t = self::ge_select($i >> 1, (int) $e[$i]);
- $r = self::ge_madd($r, $h, $t);
- $h = self::ge_p1p1_to_p3($r);
- }
- return $h;
- }
-
- /**
- * Calculates (ab + c) mod l
- * where l = 2^252 + 27742317777372353535851937790883648493
- *
- * @internal You should not use this directly from another application
- *
- * @param string $a
- * @param string $b
- * @param string $c
- * @return string
- * @throws TypeError
- */
- public static function sc_muladd($a, $b, $c)
- {
- /** @var int $a0 */
- $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
- /** @var int $a1 */
- $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
- /** @var int $a2 */
- $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
- /** @var int $a3 */
- $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
- /** @var int $a4 */
- $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
- /** @var int $a5 */
- $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
- /** @var int $a6 */
- $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
- /** @var int $a7 */
- $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
- /** @var int $a8 */
- $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
- /** @var int $a9 */
- $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
- /** @var int $a10 */
- $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
- /** @var int $a11 */
- $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
-
- /** @var int $b0 */
- $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
- /** @var int $b1 */
- $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
- /** @var int $b2 */
- $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
- /** @var int $b3 */
- $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
- /** @var int $b4 */
- $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
- /** @var int $b5 */
- $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
- /** @var int $b6 */
- $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
- /** @var int $b7 */
- $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
- /** @var int $b8 */
- $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
- /** @var int $b9 */
- $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
- /** @var int $b10 */
- $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
- /** @var int $b11 */
- $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
-
- /** @var int $c0 */
- $c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
- /** @var int $c1 */
- $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5);
- /** @var int $c2 */
- $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2);
- /** @var int $c3 */
- $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7);
- /** @var int $c4 */
- $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4);
- /** @var int $c5 */
- $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1);
- /** @var int $c6 */
- $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6);
- /** @var int $c7 */
- $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3);
- /** @var int $c8 */
- $c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
- /** @var int $c9 */
- $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5);
- /** @var int $c10 */
- $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2);
- /** @var int $c11 */
- $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);
-
- /* Can't really avoid the pyramid here: */
- $s0 = $c0 + self::mul($a0, $b0, 24);
- $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
- $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24);
- $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
- $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
- self::mul($a4, $b0, 24);
- $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
- self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
- $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
- self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24);
- $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
- self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
- $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
- self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
- self::mul($a8, $b0, 24);
- $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
- self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
- self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
- $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
- self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
- self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24);
- $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
- self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
- self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
- $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
- self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
- self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24);
- $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
- self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
- self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
- $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
- self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
- self::mul($a11, $b3, 24);
- $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
- self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
- $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
- self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24);
- $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
- self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
- $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
- self::mul($a11, $b7, 24);
- $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
- $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24);
- $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
- $s22 = self::mul($a11, $b11, 24);
- $s23 = 0;
-
- /** @var int $carry0 */
- $carry0 = ($s0 + (1 << 20)) >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry2 */
- $carry2 = ($s2 + (1 << 20)) >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry4 */
- $carry4 = ($s4 + (1 << 20)) >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry6 */
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry8 */
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry10 */
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- /** @var int $carry12 */
- $carry12 = ($s12 + (1 << 20)) >> 21;
- $s13 += $carry12;
- $s12 -= $carry12 << 21;
- /** @var int $carry14 */
- $carry14 = ($s14 + (1 << 20)) >> 21;
- $s15 += $carry14;
- $s14 -= $carry14 << 21;
- /** @var int $carry16 */
- $carry16 = ($s16 + (1 << 20)) >> 21;
- $s17 += $carry16;
- $s16 -= $carry16 << 21;
- /** @var int $carry18 */
- $carry18 = ($s18 + (1 << 20)) >> 21;
- $s19 += $carry18;
- $s18 -= $carry18 << 21;
- /** @var int $carry20 */
- $carry20 = ($s20 + (1 << 20)) >> 21;
- $s21 += $carry20;
- $s20 -= $carry20 << 21;
- /** @var int $carry22 */
- $carry22 = ($s22 + (1 << 20)) >> 21;
- $s23 += $carry22;
- $s22 -= $carry22 << 21;
-
- /** @var int $carry1 */
- $carry1 = ($s1 + (1 << 20)) >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry3 */
- $carry3 = ($s3 + (1 << 20)) >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry5 */
- $carry5 = ($s5 + (1 << 20)) >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry7 */
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry9 */
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry11 */
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
- /** @var int $carry13 */
- $carry13 = ($s13 + (1 << 20)) >> 21;
- $s14 += $carry13;
- $s13 -= $carry13 << 21;
- /** @var int $carry15 */
- $carry15 = ($s15 + (1 << 20)) >> 21;
- $s16 += $carry15;
- $s15 -= $carry15 << 21;
- /** @var int $carry17 */
- $carry17 = ($s17 + (1 << 20)) >> 21;
- $s18 += $carry17;
- $s17 -= $carry17 << 21;
- /** @var int $carry19 */
- $carry19 = ($s19 + (1 << 20)) >> 21;
- $s20 += $carry19;
- $s19 -= $carry19 << 21;
- /** @var int $carry21 */
- $carry21 = ($s21 + (1 << 20)) >> 21;
- $s22 += $carry21;
- $s21 -= $carry21 << 21;
-
- $s11 += self::mul($s23, 666643, 20);
- $s12 += self::mul($s23, 470296, 19);
- $s13 += self::mul($s23, 654183, 20);
- $s14 -= self::mul($s23, 997805, 20);
- $s15 += self::mul($s23, 136657, 18);
- $s16 -= self::mul($s23, 683901, 20);
-
- $s10 += self::mul($s22, 666643, 20);
- $s11 += self::mul($s22, 470296, 19);
- $s12 += self::mul($s22, 654183, 20);
- $s13 -= self::mul($s22, 997805, 20);
- $s14 += self::mul($s22, 136657, 18);
- $s15 -= self::mul($s22, 683901, 20);
-
- $s9 += self::mul($s21, 666643, 20);
- $s10 += self::mul($s21, 470296, 19);
- $s11 += self::mul($s21, 654183, 20);
- $s12 -= self::mul($s21, 997805, 20);
- $s13 += self::mul($s21, 136657, 18);
- $s14 -= self::mul($s21, 683901, 20);
-
- $s8 += self::mul($s20, 666643, 20);
- $s9 += self::mul($s20, 470296, 19);
- $s10 += self::mul($s20, 654183, 20);
- $s11 -= self::mul($s20, 997805, 20);
- $s12 += self::mul($s20, 136657, 18);
- $s13 -= self::mul($s20, 683901, 20);
-
- $s7 += self::mul($s19, 666643, 20);
- $s8 += self::mul($s19, 470296, 19);
- $s9 += self::mul($s19, 654183, 20);
- $s10 -= self::mul($s19, 997805, 20);
- $s11 += self::mul($s19, 136657, 18);
- $s12 -= self::mul($s19, 683901, 20);
-
- $s6 += self::mul($s18, 666643, 20);
- $s7 += self::mul($s18, 470296, 19);
- $s8 += self::mul($s18, 654183, 20);
- $s9 -= self::mul($s18, 997805, 20);
- $s10 += self::mul($s18, 136657, 18);
- $s11 -= self::mul($s18, 683901, 20);
-
- /** @var int $carry6 */
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry8 */
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry10 */
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- /** @var int $carry12 */
- $carry12 = ($s12 + (1 << 20)) >> 21;
- $s13 += $carry12;
- $s12 -= $carry12 << 21;
- /** @var int $carry14 */
- $carry14 = ($s14 + (1 << 20)) >> 21;
- $s15 += $carry14;
- $s14 -= $carry14 << 21;
- /** @var int $carry16 */
- $carry16 = ($s16 + (1 << 20)) >> 21;
- $s17 += $carry16;
- $s16 -= $carry16 << 21;
-
- /** @var int $carry7 */
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry9 */
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry11 */
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
- /** @var int $carry13 */
- $carry13 = ($s13 + (1 << 20)) >> 21;
- $s14 += $carry13;
- $s13 -= $carry13 << 21;
- /** @var int $carry15 */
- $carry15 = ($s15 + (1 << 20)) >> 21;
- $s16 += $carry15;
- $s15 -= $carry15 << 21;
-
- $s5 += self::mul($s17, 666643, 20);
- $s6 += self::mul($s17, 470296, 19);
- $s7 += self::mul($s17, 654183, 20);
- $s8 -= self::mul($s17, 997805, 20);
- $s9 += self::mul($s17, 136657, 18);
- $s10 -= self::mul($s17, 683901, 20);
-
- $s4 += self::mul($s16, 666643, 20);
- $s5 += self::mul($s16, 470296, 19);
- $s6 += self::mul($s16, 654183, 20);
- $s7 -= self::mul($s16, 997805, 20);
- $s8 += self::mul($s16, 136657, 18);
- $s9 -= self::mul($s16, 683901, 20);
-
- $s3 += self::mul($s15, 666643, 20);
- $s4 += self::mul($s15, 470296, 19);
- $s5 += self::mul($s15, 654183, 20);
- $s6 -= self::mul($s15, 997805, 20);
- $s7 += self::mul($s15, 136657, 18);
- $s8 -= self::mul($s15, 683901, 20);
-
- $s2 += self::mul($s14, 666643, 20);
- $s3 += self::mul($s14, 470296, 19);
- $s4 += self::mul($s14, 654183, 20);
- $s5 -= self::mul($s14, 997805, 20);
- $s6 += self::mul($s14, 136657, 18);
- $s7 -= self::mul($s14, 683901, 20);
-
- $s1 += self::mul($s13, 666643, 20);
- $s2 += self::mul($s13, 470296, 19);
- $s3 += self::mul($s13, 654183, 20);
- $s4 -= self::mul($s13, 997805, 20);
- $s5 += self::mul($s13, 136657, 18);
- $s6 -= self::mul($s13, 683901, 20);
-
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
- $s12 = 0;
-
- /** @var int $carry0 */
- $carry0 = ($s0 + (1 << 20)) >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry2 */
- $carry2 = ($s2 + (1 << 20)) >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry4 */
- $carry4 = ($s4 + (1 << 20)) >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry6 */
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry8 */
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry10 */
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
-
- /** @var int $carry1 */
- $carry1 = ($s1 + (1 << 20)) >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry3 */
- $carry3 = ($s3 + (1 << 20)) >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry5 */
- $carry5 = ($s5 + (1 << 20)) >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry7 */
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry9 */
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry11 */
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
-
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
- $s12 = 0;
-
- /** @var int $carry0 */
- $carry0 = $s0 >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry1 */
- $carry1 = $s1 >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry2 */
- $carry2 = $s2 >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry3 */
- $carry3 = $s3 >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry4 */
- $carry4 = $s4 >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry5 */
- $carry5 = $s5 >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry6 */
- $carry6 = $s6 >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry7 */
- $carry7 = $s7 >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry8 */
- $carry8 = $s8 >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry9 */
- $carry9 = $s9 >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry10 */
- $carry10 = $s10 >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- /** @var int $carry11 */
- $carry11 = $s11 >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
-
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
-
- /** @var int $carry0 */
- $carry0 = $s0 >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry1 */
- $carry1 = $s1 >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry2 */
- $carry2 = $s2 >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry3 */
- $carry3 = $s3 >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry4 */
- $carry4 = $s4 >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry5 */
- $carry5 = $s5 >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry6 */
- $carry6 = $s6 >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry7 */
- $carry7 = $s7 >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry8 */
- $carry8 = $s8 >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry9 */
- $carry9 = $s9 >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry10 */
- $carry10 = $s10 >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
-
- /**
- * @var array<int, int>
- */
- $arr = array(
- (int) (0xff & ($s0 >> 0)),
- (int) (0xff & ($s0 >> 8)),
- (int) (0xff & (($s0 >> 16) | $s1 << 5)),
- (int) (0xff & ($s1 >> 3)),
- (int) (0xff & ($s1 >> 11)),
- (int) (0xff & (($s1 >> 19) | $s2 << 2)),
- (int) (0xff & ($s2 >> 6)),
- (int) (0xff & (($s2 >> 14) | $s3 << 7)),
- (int) (0xff & ($s3 >> 1)),
- (int) (0xff & ($s3 >> 9)),
- (int) (0xff & (($s3 >> 17) | $s4 << 4)),
- (int) (0xff & ($s4 >> 4)),
- (int) (0xff & ($s4 >> 12)),
- (int) (0xff & (($s4 >> 20) | $s5 << 1)),
- (int) (0xff & ($s5 >> 7)),
- (int) (0xff & (($s5 >> 15) | $s6 << 6)),
- (int) (0xff & ($s6 >> 2)),
- (int) (0xff & ($s6 >> 10)),
- (int) (0xff & (($s6 >> 18) | $s7 << 3)),
- (int) (0xff & ($s7 >> 5)),
- (int) (0xff & ($s7 >> 13)),
- (int) (0xff & ($s8 >> 0)),
- (int) (0xff & ($s8 >> 8)),
- (int) (0xff & (($s8 >> 16) | $s9 << 5)),
- (int) (0xff & ($s9 >> 3)),
- (int) (0xff & ($s9 >> 11)),
- (int) (0xff & (($s9 >> 19) | $s10 << 2)),
- (int) (0xff & ($s10 >> 6)),
- (int) (0xff & (($s10 >> 14) | $s11 << 7)),
- (int) (0xff & ($s11 >> 1)),
- (int) (0xff & ($s11 >> 9)),
- 0xff & ($s11 >> 17)
- );
- return self::intArrayToString($arr);
- }
-
- /**
- * @internal You should not use this directly from another application
- *
- * @param string $s
- * @return string
- * @throws TypeError
- */
- public static function sc_reduce($s)
- {
- /** @var int $s0 */
- $s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
- /** @var int $s1 */
- $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5);
- /** @var int $s2 */
- $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2);
- /** @var int $s3 */
- $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7);
- /** @var int $s4 */
- $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4);
- /** @var int $s5 */
- $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1);
- /** @var int $s6 */
- $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6);
- /** @var int $s7 */
- $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3);
- /** @var int $s8 */
- $s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
- /** @var int $s9 */
- $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5);
- /** @var int $s10 */
- $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2);
- /** @var int $s11 */
- $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7);
- /** @var int $s12 */
- $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4);
- /** @var int $s13 */
- $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1);
- /** @var int $s14 */
- $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6);
- /** @var int $s15 */
- $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3);
- /** @var int $s16 */
- $s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
- /** @var int $s17 */
- $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5);
- /** @var int $s18 */
- $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2);
- /** @var int $s19 */
- $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7);
- /** @var int $s20 */
- $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4);
- /** @var int $s21 */
- $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1);
- /** @var int $s22 */
- $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6);
- /** @var int $s23 */
- $s23 = (self::load_4(self::substr($s, 60, 4)) >> 3);
-
- $s11 += self::mul($s23, 666643, 20);
- $s12 += self::mul($s23, 470296, 19);
- $s13 += self::mul($s23, 654183, 20);
- $s14 -= self::mul($s23, 997805, 20);
- $s15 += self::mul($s23, 136657, 18);
- $s16 -= self::mul($s23, 683901, 20);
-
- $s10 += self::mul($s22, 666643, 20);
- $s11 += self::mul($s22, 470296, 19);
- $s12 += self::mul($s22, 654183, 20);
- $s13 -= self::mul($s22, 997805, 20);
- $s14 += self::mul($s22, 136657, 18);
- $s15 -= self::mul($s22, 683901, 20);
-
- $s9 += self::mul($s21, 666643, 20);
- $s10 += self::mul($s21, 470296, 19);
- $s11 += self::mul($s21, 654183, 20);
- $s12 -= self::mul($s21, 997805, 20);
- $s13 += self::mul($s21, 136657, 18);
- $s14 -= self::mul($s21, 683901, 20);
-
- $s8 += self::mul($s20, 666643, 20);
- $s9 += self::mul($s20, 470296, 19);
- $s10 += self::mul($s20, 654183, 20);
- $s11 -= self::mul($s20, 997805, 20);
- $s12 += self::mul($s20, 136657, 18);
- $s13 -= self::mul($s20, 683901, 20);
-
- $s7 += self::mul($s19, 666643, 20);
- $s8 += self::mul($s19, 470296, 19);
- $s9 += self::mul($s19, 654183, 20);
- $s10 -= self::mul($s19, 997805, 20);
- $s11 += self::mul($s19, 136657, 18);
- $s12 -= self::mul($s19, 683901, 20);
-
- $s6 += self::mul($s18, 666643, 20);
- $s7 += self::mul($s18, 470296, 19);
- $s8 += self::mul($s18, 654183, 20);
- $s9 -= self::mul($s18, 997805, 20);
- $s10 += self::mul($s18, 136657, 18);
- $s11 -= self::mul($s18, 683901, 20);
-
- /** @var int $carry6 */
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry8 */
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry10 */
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- /** @var int $carry12 */
- $carry12 = ($s12 + (1 << 20)) >> 21;
- $s13 += $carry12;
- $s12 -= $carry12 << 21;
- /** @var int $carry14 */
- $carry14 = ($s14 + (1 << 20)) >> 21;
- $s15 += $carry14;
- $s14 -= $carry14 << 21;
- /** @var int $carry16 */
- $carry16 = ($s16 + (1 << 20)) >> 21;
- $s17 += $carry16;
- $s16 -= $carry16 << 21;
-
- /** @var int $carry7 */
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry9 */
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry11 */
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
- /** @var int $carry13 */
- $carry13 = ($s13 + (1 << 20)) >> 21;
- $s14 += $carry13;
- $s13 -= $carry13 << 21;
- /** @var int $carry15 */
- $carry15 = ($s15 + (1 << 20)) >> 21;
- $s16 += $carry15;
- $s15 -= $carry15 << 21;
-
- $s5 += self::mul($s17, 666643, 20);
- $s6 += self::mul($s17, 470296, 19);
- $s7 += self::mul($s17, 654183, 20);
- $s8 -= self::mul($s17, 997805, 20);
- $s9 += self::mul($s17, 136657, 18);
- $s10 -= self::mul($s17, 683901, 20);
-
- $s4 += self::mul($s16, 666643, 20);
- $s5 += self::mul($s16, 470296, 19);
- $s6 += self::mul($s16, 654183, 20);
- $s7 -= self::mul($s16, 997805, 20);
- $s8 += self::mul($s16, 136657, 18);
- $s9 -= self::mul($s16, 683901, 20);
-
- $s3 += self::mul($s15, 666643, 20);
- $s4 += self::mul($s15, 470296, 19);
- $s5 += self::mul($s15, 654183, 20);
- $s6 -= self::mul($s15, 997805, 20);
- $s7 += self::mul($s15, 136657, 18);
- $s8 -= self::mul($s15, 683901, 20);
-
- $s2 += self::mul($s14, 666643, 20);
- $s3 += self::mul($s14, 470296, 19);
- $s4 += self::mul($s14, 654183, 20);
- $s5 -= self::mul($s14, 997805, 20);
- $s6 += self::mul($s14, 136657, 18);
- $s7 -= self::mul($s14, 683901, 20);
-
- $s1 += self::mul($s13, 666643, 20);
- $s2 += self::mul($s13, 470296, 19);
- $s3 += self::mul($s13, 654183, 20);
- $s4 -= self::mul($s13, 997805, 20);
- $s5 += self::mul($s13, 136657, 18);
- $s6 -= self::mul($s13, 683901, 20);
-
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
- $s12 = 0;
-
- /** @var int $carry0 */
- $carry0 = ($s0 + (1 << 20)) >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry2 */
- $carry2 = ($s2 + (1 << 20)) >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry4 */
- $carry4 = ($s4 + (1 << 20)) >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry6 */
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry8 */
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry10 */
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
-
- /** @var int $carry1 */
- $carry1 = ($s1 + (1 << 20)) >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry3 */
- $carry3 = ($s3 + (1 << 20)) >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry5 */
- $carry5 = ($s5 + (1 << 20)) >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry7 */
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry9 */
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry11 */
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
-
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
- $s12 = 0;
-
- /** @var int $carry0 */
- $carry0 = $s0 >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry1 */
- $carry1 = $s1 >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry2 */
- $carry2 = $s2 >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry3 */
- $carry3 = $s3 >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry4 */
- $carry4 = $s4 >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry5 */
- $carry5 = $s5 >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry6 */
- $carry6 = $s6 >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry7 */
- $carry7 = $s7 >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry8 */
- $carry8 = $s8 >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry9 */
- $carry9 = $s9 >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry10 */
- $carry10 = $s10 >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- /** @var int $carry11 */
- $carry11 = $s11 >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
-
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
-
- /** @var int $carry0 */
- $carry0 = $s0 >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- /** @var int $carry1 */
- $carry1 = $s1 >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- /** @var int $carry2 */
- $carry2 = $s2 >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- /** @var int $carry3 */
- $carry3 = $s3 >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- /** @var int $carry4 */
- $carry4 = $s4 >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- /** @var int $carry5 */
- $carry5 = $s5 >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- /** @var int $carry6 */
- $carry6 = $s6 >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- /** @var int $carry7 */
- $carry7 = $s7 >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- /** @var int $carry8 */
- $carry8 = $s8 >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- /** @var int $carry9 */
- $carry9 = $s9 >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- /** @var int $carry10 */
- $carry10 = $s10 >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
-
- /**
- * @var array<int, int>
- */
- $arr = array(
- (int) ($s0 >> 0),
- (int) ($s0 >> 8),
- (int) (($s0 >> 16) | $s1 << 5),
- (int) ($s1 >> 3),
- (int) ($s1 >> 11),
- (int) (($s1 >> 19) | $s2 << 2),
- (int) ($s2 >> 6),
- (int) (($s2 >> 14) | $s3 << 7),
- (int) ($s3 >> 1),
- (int) ($s3 >> 9),
- (int) (($s3 >> 17) | $s4 << 4),
- (int) ($s4 >> 4),
- (int) ($s4 >> 12),
- (int) (($s4 >> 20) | $s5 << 1),
- (int) ($s5 >> 7),
- (int) (($s5 >> 15) | $s6 << 6),
- (int) ($s6 >> 2),
- (int) ($s6 >> 10),
- (int) (($s6 >> 18) | $s7 << 3),
- (int) ($s7 >> 5),
- (int) ($s7 >> 13),
- (int) ($s8 >> 0),
- (int) ($s8 >> 8),
- (int) (($s8 >> 16) | $s9 << 5),
- (int) ($s9 >> 3),
- (int) ($s9 >> 11),
- (int) (($s9 >> 19) | $s10 << 2),
- (int) ($s10 >> 6),
- (int) (($s10 >> 14) | $s11 << 7),
- (int) ($s11 >> 1),
- (int) ($s11 >> 9),
- (int) $s11 >> 17
- );
- return self::intArrayToString($arr);
- }
-
- /**
- * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
- * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
- */
- public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A)
- {
- /** @var array<int, int> $aslide */
- $aslide = array(
- 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
- 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
- 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
- 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
- 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
- 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
- );
-
- /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
- $Ai = array();
-
- # ge_p3_to_cached(&Ai[0], A);
- $Ai[0] = self::ge_p3_to_cached($A);
- # ge_p3_dbl(&t, A);
- $t = self::ge_p3_dbl($A);
- # ge_p1p1_to_p3(&A2, &t);
- $A2 = self::ge_p1p1_to_p3($t);
-
- for ($i = 1; $i < 8; ++$i) {
- # ge_add(&t, &A2, &Ai[0]);
- $t = self::ge_add($A2, $Ai[$i - 1]);
- # ge_p1p1_to_p3(&u, &t);
- $u = self::ge_p1p1_to_p3($t);
- # ge_p3_to_cached(&Ai[i], &u);
- $Ai[$i] = self::ge_p3_to_cached($u);
- }
-
- $r = self::ge_p3_0();
- for ($i = 252; $i >= 0; --$i) {
- $t = self::ge_p3_dbl($r);
- if ($aslide[$i] > 0) {
- # ge_p1p1_to_p3(&u, &t);
- $u = self::ge_p1p1_to_p3($t);
- # ge_add(&t, &u, &Ai[aslide[i] / 2]);
- $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
- } elseif ($aslide[$i] < 0) {
- # ge_p1p1_to_p3(&u, &t);
- $u = self::ge_p1p1_to_p3($t);
- # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
- $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
- }
- }
-
- # ge_p1p1_to_p3(r, &t);
- return self::ge_p1p1_to_p3($t);
- }
-
- /**
- * @param string $a
- * @param string $b
- * @return string
- */
- public static function sc25519_mul($a, $b)
- {
- // int64_t a0 = 2097151 & load_3(a);
- // int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
- // int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
- // int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
- // int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
- // int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
- // int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
- // int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
- // int64_t a8 = 2097151 & load_3(a + 21);
- // int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
- // int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
- // int64_t a11 = (load_4(a + 28) >> 7);
- $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
- $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
- $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
- $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
- $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
- $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
- $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
- $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
- $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
- $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
- $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
- $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
-
- // int64_t b0 = 2097151 & load_3(b);
- // int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
- // int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
- // int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
- // int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
- // int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
- // int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
- // int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
- // int64_t b8 = 2097151 & load_3(b + 21);
- // int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
- // int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
- // int64_t b11 = (load_4(b + 28) >> 7);
- $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
- $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
- $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
- $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
- $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
- $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
- $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
- $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
- $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
- $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
- $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
- $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
-
- // s0 = a0 * b0;
- // s1 = a0 * b1 + a1 * b0;
- // s2 = a0 * b2 + a1 * b1 + a2 * b0;
- // s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
- // s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
- // s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
- // s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
- // s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
- // a6 * b1 + a7 * b0;
- // s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
- // a6 * b2 + a7 * b1 + a8 * b0;
- // s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
- // a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
- // s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
- // a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
- // s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
- // a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
- // s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 +
- // a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
- // s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 +
- // a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
- // s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 +
- // a9 * b5 + a10 * b4 + a11 * b3;
- // s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 +
- // a10 * b5 + a11 * b4;
- // s16 =
- // a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
- // s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
- // s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
- // s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
- // s20 = a9 * b11 + a10 * b10 + a11 * b9;
- // s21 = a10 * b11 + a11 * b10;
- // s22 = a11 * b11;
- // s23 = 0;
- $s0 = self::mul($a0, $b0, 22);
- $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22);
- $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22);
- $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22);
- $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) +
- self::mul($a4, $b0, 22);
- $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) +
- self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22);
- $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) +
- self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22);
- $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) +
- self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22);
- $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) +
- self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) +
- self::mul($a8, $b0, 22);
- $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) +
- self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) +
- self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22);
- $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) +
- self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) +
- self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22);
- $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) +
- self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) +
- self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22);
- $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) +
- self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) +
- self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22);
- $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) +
- self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) +
- self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22);
- $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) +
- self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) +
- self::mul($a11, $b3, 22);
- $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) +
- self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22);
- $s16 =
- self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) +
- self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22);
- $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) +
- self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22);
- $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22)
- + self::mul($a11, $b7, 22);
- $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) +
- self::mul($a11, $b8, 22);
- $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22);
- $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22);
- $s22 = self::mul($a11, $b11, 22);
- $s23 = 0;
-
- // carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
- // s1 += carry0;
- // s0 -= carry0 * ((uint64_t) 1L << 21);
- $carry0 = ($s0 + (1 << 20)) >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- // carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
- // s3 += carry2;
- // s2 -= carry2 * ((uint64_t) 1L << 21);
- $carry2 = ($s2 + (1 << 20)) >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- // carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
- // s5 += carry4;
- // s4 -= carry4 * ((uint64_t) 1L << 21);
- $carry4 = ($s4 + (1 << 20)) >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- // carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
- // s7 += carry6;
- // s6 -= carry6 * ((uint64_t) 1L << 21);
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- // carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
- // s9 += carry8;
- // s8 -= carry8 * ((uint64_t) 1L << 21);
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- // carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
- // s11 += carry10;
- // s10 -= carry10 * ((uint64_t) 1L << 21);
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- // carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
- // s13 += carry12;
- // s12 -= carry12 * ((uint64_t) 1L << 21);
- $carry12 = ($s12 + (1 << 20)) >> 21;
- $s13 += $carry12;
- $s12 -= $carry12 << 21;
- // carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
- // s15 += carry14;
- // s14 -= carry14 * ((uint64_t) 1L << 21);
- $carry14 = ($s14 + (1 << 20)) >> 21;
- $s15 += $carry14;
- $s14 -= $carry14 << 21;
- // carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
- // s17 += carry16;
- // s16 -= carry16 * ((uint64_t) 1L << 21);
- $carry16 = ($s16 + (1 << 20)) >> 21;
- $s17 += $carry16;
- $s16 -= $carry16 << 21;
- // carry18 = (s18 + (int64_t) (1L << 20)) >> 21;
- // s19 += carry18;
- // s18 -= carry18 * ((uint64_t) 1L << 21);
- $carry18 = ($s18 + (1 << 20)) >> 21;
- $s19 += $carry18;
- $s18 -= $carry18 << 21;
- // carry20 = (s20 + (int64_t) (1L << 20)) >> 21;
- // s21 += carry20;
- // s20 -= carry20 * ((uint64_t) 1L << 21);
- $carry20 = ($s20 + (1 << 20)) >> 21;
- $s21 += $carry20;
- $s20 -= $carry20 << 21;
- // carry22 = (s22 + (int64_t) (1L << 20)) >> 21;
- // s23 += carry22;
- // s22 -= carry22 * ((uint64_t) 1L << 21);
- $carry22 = ($s22 + (1 << 20)) >> 21;
- $s23 += $carry22;
- $s22 -= $carry22 << 21;
-
- // carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
- // s2 += carry1;
- // s1 -= carry1 * ((uint64_t) 1L << 21);
- $carry1 = ($s1 + (1 << 20)) >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- // carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
- // s4 += carry3;
- // s3 -= carry3 * ((uint64_t) 1L << 21);
- $carry3 = ($s3 + (1 << 20)) >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- // carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
- // s6 += carry5;
- // s5 -= carry5 * ((uint64_t) 1L << 21);
- $carry5 = ($s5 + (1 << 20)) >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- // carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
- // s8 += carry7;
- // s7 -= carry7 * ((uint64_t) 1L << 21);
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- // carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
- // s10 += carry9;
- // s9 -= carry9 * ((uint64_t) 1L << 21);
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- // carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
- // s12 += carry11;
- // s11 -= carry11 * ((uint64_t) 1L << 21);
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
- // carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
- // s14 += carry13;
- // s13 -= carry13 * ((uint64_t) 1L << 21);
- $carry13 = ($s13 + (1 << 20)) >> 21;
- $s14 += $carry13;
- $s13 -= $carry13 << 21;
- // carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
- // s16 += carry15;
- // s15 -= carry15 * ((uint64_t) 1L << 21);
- $carry15 = ($s15 + (1 << 20)) >> 21;
- $s16 += $carry15;
- $s15 -= $carry15 << 21;
- // carry17 = (s17 + (int64_t) (1L << 20)) >> 21;
- // s18 += carry17;
- // s17 -= carry17 * ((uint64_t) 1L << 21);
- $carry17 = ($s17 + (1 << 20)) >> 21;
- $s18 += $carry17;
- $s17 -= $carry17 << 21;
- // carry19 = (s19 + (int64_t) (1L << 20)) >> 21;
- // s20 += carry19;
- // s19 -= carry19 * ((uint64_t) 1L << 21);
- $carry19 = ($s19 + (1 << 20)) >> 21;
- $s20 += $carry19;
- $s19 -= $carry19 << 21;
- // carry21 = (s21 + (int64_t) (1L << 20)) >> 21;
- // s22 += carry21;
- // s21 -= carry21 * ((uint64_t) 1L << 21);
- $carry21 = ($s21 + (1 << 20)) >> 21;
- $s22 += $carry21;
- $s21 -= $carry21 << 21;
-
- // s11 += s23 * 666643;
- // s12 += s23 * 470296;
- // s13 += s23 * 654183;
- // s14 -= s23 * 997805;
- // s15 += s23 * 136657;
- // s16 -= s23 * 683901;
- $s11 += self::mul($s23, 666643, 20);
- $s12 += self::mul($s23, 470296, 19);
- $s13 += self::mul($s23, 654183, 20);
- $s14 -= self::mul($s23, 997805, 20);
- $s15 += self::mul($s23, 136657, 18);
- $s16 -= self::mul($s23, 683901, 20);
-
- // s10 += s22 * 666643;
- // s11 += s22 * 470296;
- // s12 += s22 * 654183;
- // s13 -= s22 * 997805;
- // s14 += s22 * 136657;
- // s15 -= s22 * 683901;
- $s10 += self::mul($s22, 666643, 20);
- $s11 += self::mul($s22, 470296, 19);
- $s12 += self::mul($s22, 654183, 20);
- $s13 -= self::mul($s22, 997805, 20);
- $s14 += self::mul($s22, 136657, 18);
- $s15 -= self::mul($s22, 683901, 20);
-
- // s9 += s21 * 666643;
- // s10 += s21 * 470296;
- // s11 += s21 * 654183;
- // s12 -= s21 * 997805;
- // s13 += s21 * 136657;
- // s14 -= s21 * 683901;
- $s9 += self::mul($s21, 666643, 20);
- $s10 += self::mul($s21, 470296, 19);
- $s11 += self::mul($s21, 654183, 20);
- $s12 -= self::mul($s21, 997805, 20);
- $s13 += self::mul($s21, 136657, 18);
- $s14 -= self::mul($s21, 683901, 20);
-
- // s8 += s20 * 666643;
- // s9 += s20 * 470296;
- // s10 += s20 * 654183;
- // s11 -= s20 * 997805;
- // s12 += s20 * 136657;
- // s13 -= s20 * 683901;
- $s8 += self::mul($s20, 666643, 20);
- $s9 += self::mul($s20, 470296, 19);
- $s10 += self::mul($s20, 654183, 20);
- $s11 -= self::mul($s20, 997805, 20);
- $s12 += self::mul($s20, 136657, 18);
- $s13 -= self::mul($s20, 683901, 20);
-
- // s7 += s19 * 666643;
- // s8 += s19 * 470296;
- // s9 += s19 * 654183;
- // s10 -= s19 * 997805;
- // s11 += s19 * 136657;
- // s12 -= s19 * 683901;
- $s7 += self::mul($s19, 666643, 20);
- $s8 += self::mul($s19, 470296, 19);
- $s9 += self::mul($s19, 654183, 20);
- $s10 -= self::mul($s19, 997805, 20);
- $s11 += self::mul($s19, 136657, 18);
- $s12 -= self::mul($s19, 683901, 20);
-
- // s6 += s18 * 666643;
- // s7 += s18 * 470296;
- // s8 += s18 * 654183;
- // s9 -= s18 * 997805;
- // s10 += s18 * 136657;
- // s11 -= s18 * 683901;
- $s6 += self::mul($s18, 666643, 20);
- $s7 += self::mul($s18, 470296, 19);
- $s8 += self::mul($s18, 654183, 20);
- $s9 -= self::mul($s18, 997805, 20);
- $s10 += self::mul($s18, 136657, 18);
- $s11 -= self::mul($s18, 683901, 20);
-
- // carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
- // s7 += carry6;
- // s6 -= carry6 * ((uint64_t) 1L << 21);
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- // carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
- // s9 += carry8;
- // s8 -= carry8 * ((uint64_t) 1L << 21);
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- // carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
- // s11 += carry10;
- // s10 -= carry10 * ((uint64_t) 1L << 21);
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- // carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
- // s13 += carry12;
- // s12 -= carry12 * ((uint64_t) 1L << 21);
- $carry12 = ($s12 + (1 << 20)) >> 21;
- $s13 += $carry12;
- $s12 -= $carry12 << 21;
- // carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
- // s15 += carry14;
- // s14 -= carry14 * ((uint64_t) 1L << 21);
- $carry14 = ($s14 + (1 << 20)) >> 21;
- $s15 += $carry14;
- $s14 -= $carry14 << 21;
- // carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
- // s17 += carry16;
- // s16 -= carry16 * ((uint64_t) 1L << 21);
- $carry16 = ($s16 + (1 << 20)) >> 21;
- $s17 += $carry16;
- $s16 -= $carry16 << 21;
-
- // carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
- // s8 += carry7;
- // s7 -= carry7 * ((uint64_t) 1L << 21);
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- // carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
- // s10 += carry9;
- // s9 -= carry9 * ((uint64_t) 1L << 21);
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- // carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
- // s12 += carry11;
- // s11 -= carry11 * ((uint64_t) 1L << 21);
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
- // carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
- // s14 += carry13;
- // s13 -= carry13 * ((uint64_t) 1L << 21);
- $carry13 = ($s13 + (1 << 20)) >> 21;
- $s14 += $carry13;
- $s13 -= $carry13 << 21;
- // carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
- // s16 += carry15;
- // s15 -= carry15 * ((uint64_t) 1L << 21);
- $carry15 = ($s15 + (1 << 20)) >> 21;
- $s16 += $carry15;
- $s15 -= $carry15 << 21;
-
- // s5 += s17 * 666643;
- // s6 += s17 * 470296;
- // s7 += s17 * 654183;
- // s8 -= s17 * 997805;
- // s9 += s17 * 136657;
- // s10 -= s17 * 683901;
- $s5 += self::mul($s17, 666643, 20);
- $s6 += self::mul($s17, 470296, 19);
- $s7 += self::mul($s17, 654183, 20);
- $s8 -= self::mul($s17, 997805, 20);
- $s9 += self::mul($s17, 136657, 18);
- $s10 -= self::mul($s17, 683901, 20);
-
- // s4 += s16 * 666643;
- // s5 += s16 * 470296;
- // s6 += s16 * 654183;
- // s7 -= s16 * 997805;
- // s8 += s16 * 136657;
- // s9 -= s16 * 683901;
- $s4 += self::mul($s16, 666643, 20);
- $s5 += self::mul($s16, 470296, 19);
- $s6 += self::mul($s16, 654183, 20);
- $s7 -= self::mul($s16, 997805, 20);
- $s8 += self::mul($s16, 136657, 18);
- $s9 -= self::mul($s16, 683901, 20);
-
- // s3 += s15 * 666643;
- // s4 += s15 * 470296;
- // s5 += s15 * 654183;
- // s6 -= s15 * 997805;
- // s7 += s15 * 136657;
- // s8 -= s15 * 683901;
- $s3 += self::mul($s15, 666643, 20);
- $s4 += self::mul($s15, 470296, 19);
- $s5 += self::mul($s15, 654183, 20);
- $s6 -= self::mul($s15, 997805, 20);
- $s7 += self::mul($s15, 136657, 18);
- $s8 -= self::mul($s15, 683901, 20);
-
- // s2 += s14 * 666643;
- // s3 += s14 * 470296;
- // s4 += s14 * 654183;
- // s5 -= s14 * 997805;
- // s6 += s14 * 136657;
- // s7 -= s14 * 683901;
- $s2 += self::mul($s14, 666643, 20);
- $s3 += self::mul($s14, 470296, 19);
- $s4 += self::mul($s14, 654183, 20);
- $s5 -= self::mul($s14, 997805, 20);
- $s6 += self::mul($s14, 136657, 18);
- $s7 -= self::mul($s14, 683901, 20);
-
- // s1 += s13 * 666643;
- // s2 += s13 * 470296;
- // s3 += s13 * 654183;
- // s4 -= s13 * 997805;
- // s5 += s13 * 136657;
- // s6 -= s13 * 683901;
- $s1 += self::mul($s13, 666643, 20);
- $s2 += self::mul($s13, 470296, 19);
- $s3 += self::mul($s13, 654183, 20);
- $s4 -= self::mul($s13, 997805, 20);
- $s5 += self::mul($s13, 136657, 18);
- $s6 -= self::mul($s13, 683901, 20);
-
- // s0 += s12 * 666643;
- // s1 += s12 * 470296;
- // s2 += s12 * 654183;
- // s3 -= s12 * 997805;
- // s4 += s12 * 136657;
- // s5 -= s12 * 683901;
- // s12 = 0;
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
- $s12 = 0;
-
- // carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
- // s1 += carry0;
- // s0 -= carry0 * ((uint64_t) 1L << 21);
- $carry0 = ($s0 + (1 << 20)) >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- // carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
- // s3 += carry2;
- // s2 -= carry2 * ((uint64_t) 1L << 21);
- $carry2 = ($s2 + (1 << 20)) >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- // carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
- // s5 += carry4;
- // s4 -= carry4 * ((uint64_t) 1L << 21);
- $carry4 = ($s4 + (1 << 20)) >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- // carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
- // s7 += carry6;
- // s6 -= carry6 * ((uint64_t) 1L << 21);
- $carry6 = ($s6 + (1 << 20)) >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- // carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
- // s9 += carry8;
- // s8 -= carry8 * ((uint64_t) 1L << 21);
- $carry8 = ($s8 + (1 << 20)) >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- // carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
- // s11 += carry10;
- // s10 -= carry10 * ((uint64_t) 1L << 21);
- $carry10 = ($s10 + (1 << 20)) >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
-
- // carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
- // s2 += carry1;
- // s1 -= carry1 * ((uint64_t) 1L << 21);
- $carry1 = ($s1 + (1 << 20)) >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- // carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
- // s4 += carry3;
- // s3 -= carry3 * ((uint64_t) 1L << 21);
- $carry3 = ($s3 + (1 << 20)) >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- // carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
- // s6 += carry5;
- // s5 -= carry5 * ((uint64_t) 1L << 21);
- $carry5 = ($s5 + (1 << 20)) >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- // carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
- // s8 += carry7;
- // s7 -= carry7 * ((uint64_t) 1L << 21);
- $carry7 = ($s7 + (1 << 20)) >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- // carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
- // s10 += carry9;
- // s9 -= carry9 * ((uint64_t) 1L << 21);
- $carry9 = ($s9 + (1 << 20)) >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- // carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
- // s12 += carry11;
- // s11 -= carry11 * ((uint64_t) 1L << 21);
- $carry11 = ($s11 + (1 << 20)) >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
-
- // s0 += s12 * 666643;
- // s1 += s12 * 470296;
- // s2 += s12 * 654183;
- // s3 -= s12 * 997805;
- // s4 += s12 * 136657;
- // s5 -= s12 * 683901;
- // s12 = 0;
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
- $s12 = 0;
-
- // carry0 = s0 >> 21;
- // s1 += carry0;
- // s0 -= carry0 * ((uint64_t) 1L << 21);
- $carry0 = $s0 >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- // carry1 = s1 >> 21;
- // s2 += carry1;
- // s1 -= carry1 * ((uint64_t) 1L << 21);
- $carry1 = $s1 >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- // carry2 = s2 >> 21;
- // s3 += carry2;
- // s2 -= carry2 * ((uint64_t) 1L << 21);
- $carry2 = $s2 >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- // carry3 = s3 >> 21;
- // s4 += carry3;
- // s3 -= carry3 * ((uint64_t) 1L << 21);
- $carry3 = $s3 >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- // carry4 = s4 >> 21;
- // s5 += carry4;
- // s4 -= carry4 * ((uint64_t) 1L << 21);
- $carry4 = $s4 >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- // carry5 = s5 >> 21;
- // s6 += carry5;
- // s5 -= carry5 * ((uint64_t) 1L << 21);
- $carry5 = $s5 >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- // carry6 = s6 >> 21;
- // s7 += carry6;
- // s6 -= carry6 * ((uint64_t) 1L << 21);
- $carry6 = $s6 >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- // carry7 = s7 >> 21;
- // s8 += carry7;
- // s7 -= carry7 * ((uint64_t) 1L << 21);
- $carry7 = $s7 >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- // carry8 = s8 >> 21;
- // s9 += carry8;
- // s8 -= carry8 * ((uint64_t) 1L << 21);
- $carry8 = $s8 >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- // carry9 = s9 >> 21;
- // s10 += carry9;
- // s9 -= carry9 * ((uint64_t) 1L << 21);
- $carry9 = $s9 >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- // carry10 = s10 >> 21;
- // s11 += carry10;
- // s10 -= carry10 * ((uint64_t) 1L << 21);
- $carry10 = $s10 >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
- // carry11 = s11 >> 21;
- // s12 += carry11;
- // s11 -= carry11 * ((uint64_t) 1L << 21);
- $carry11 = $s11 >> 21;
- $s12 += $carry11;
- $s11 -= $carry11 << 21;
-
- // s0 += s12 * 666643;
- // s1 += s12 * 470296;
- // s2 += s12 * 654183;
- // s3 -= s12 * 997805;
- // s4 += s12 * 136657;
- // s5 -= s12 * 683901;
- $s0 += self::mul($s12, 666643, 20);
- $s1 += self::mul($s12, 470296, 19);
- $s2 += self::mul($s12, 654183, 20);
- $s3 -= self::mul($s12, 997805, 20);
- $s4 += self::mul($s12, 136657, 18);
- $s5 -= self::mul($s12, 683901, 20);
-
- // carry0 = s0 >> 21;
- // s1 += carry0;
- // s0 -= carry0 * ((uint64_t) 1L << 21);
- $carry0 = $s0 >> 21;
- $s1 += $carry0;
- $s0 -= $carry0 << 21;
- // carry1 = s1 >> 21;
- // s2 += carry1;
- // s1 -= carry1 * ((uint64_t) 1L << 21);
- $carry1 = $s1 >> 21;
- $s2 += $carry1;
- $s1 -= $carry1 << 21;
- // carry2 = s2 >> 21;
- // s3 += carry2;
- // s2 -= carry2 * ((uint64_t) 1L << 21);
- $carry2 = $s2 >> 21;
- $s3 += $carry2;
- $s2 -= $carry2 << 21;
- // carry3 = s3 >> 21;
- // s4 += carry3;
- // s3 -= carry3 * ((uint64_t) 1L << 21);
- $carry3 = $s3 >> 21;
- $s4 += $carry3;
- $s3 -= $carry3 << 21;
- // carry4 = s4 >> 21;
- // s5 += carry4;
- // s4 -= carry4 * ((uint64_t) 1L << 21);
- $carry4 = $s4 >> 21;
- $s5 += $carry4;
- $s4 -= $carry4 << 21;
- // carry5 = s5 >> 21;
- // s6 += carry5;
- // s5 -= carry5 * ((uint64_t) 1L << 21);
- $carry5 = $s5 >> 21;
- $s6 += $carry5;
- $s5 -= $carry5 << 21;
- // carry6 = s6 >> 21;
- // s7 += carry6;
- // s6 -= carry6 * ((uint64_t) 1L << 21);
- $carry6 = $s6 >> 21;
- $s7 += $carry6;
- $s6 -= $carry6 << 21;
- // carry7 = s7 >> 21;
- // s8 += carry7;
- // s7 -= carry7 * ((uint64_t) 1L << 21);
- $carry7 = $s7 >> 21;
- $s8 += $carry7;
- $s7 -= $carry7 << 21;
- // carry8 = s8 >> 21;
- // s9 += carry8;
- // s8 -= carry8 * ((uint64_t) 1L << 21);
- $carry8 = $s8 >> 21;
- $s9 += $carry8;
- $s8 -= $carry8 << 21;
- // carry9 = s9 >> 21;
- // s10 += carry9;
- // s9 -= carry9 * ((uint64_t) 1L << 21);
- $carry9 = $s9 >> 21;
- $s10 += $carry9;
- $s9 -= $carry9 << 21;
- // carry10 = s10 >> 21;
- // s11 += carry10;
- // s10 -= carry10 * ((uint64_t) 1L << 21);
- $carry10 = $s10 >> 21;
- $s11 += $carry10;
- $s10 -= $carry10 << 21;
-
- $s = array_fill(0, 32, 0);
- // s[0] = s0 >> 0;
- $s[0] = $s0 >> 0;
- // s[1] = s0 >> 8;
- $s[1] = $s0 >> 8;
- // s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5));
- $s[2] = ($s0 >> 16) | ($s1 << 5);
- // s[3] = s1 >> 3;
- $s[3] = $s1 >> 3;
- // s[4] = s1 >> 11;
- $s[4] = $s1 >> 11;
- // s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2));
- $s[5] = ($s1 >> 19) | ($s2 << 2);
- // s[6] = s2 >> 6;
- $s[6] = $s2 >> 6;
- // s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7));
- $s[7] = ($s2 >> 14) | ($s3 << 7);
- // s[8] = s3 >> 1;
- $s[8] = $s3 >> 1;
- // s[9] = s3 >> 9;
- $s[9] = $s3 >> 9;
- // s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4));
- $s[10] = ($s3 >> 17) | ($s4 << 4);
- // s[11] = s4 >> 4;
- $s[11] = $s4 >> 4;
- // s[12] = s4 >> 12;
- $s[12] = $s4 >> 12;
- // s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1));
- $s[13] = ($s4 >> 20) | ($s5 << 1);
- // s[14] = s5 >> 7;
- $s[14] = $s5 >> 7;
- // s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6));
- $s[15] = ($s5 >> 15) | ($s6 << 6);
- // s[16] = s6 >> 2;
- $s[16] = $s6 >> 2;
- // s[17] = s6 >> 10;
- $s[17] = $s6 >> 10;
- // s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3));
- $s[18] = ($s6 >> 18) | ($s7 << 3);
- // s[19] = s7 >> 5;
- $s[19] = $s7 >> 5;
- // s[20] = s7 >> 13;
- $s[20] = $s7 >> 13;
- // s[21] = s8 >> 0;
- $s[21] = $s8 >> 0;
- // s[22] = s8 >> 8;
- $s[22] = $s8 >> 8;
- // s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5));
- $s[23] = ($s8 >> 16) | ($s9 << 5);
- // s[24] = s9 >> 3;
- $s[24] = $s9 >> 3;
- // s[25] = s9 >> 11;
- $s[25] = $s9 >> 11;
- // s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2));
- $s[26] = ($s9 >> 19) | ($s10 << 2);
- // s[27] = s10 >> 6;
- $s[27] = $s10 >> 6;
- // s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7));
- $s[28] = ($s10 >> 14) | ($s11 << 7);
- // s[29] = s11 >> 1;
- $s[29] = $s11 >> 1;
- // s[30] = s11 >> 9;
- $s[30] = $s11 >> 9;
- // s[31] = s11 >> 17;
- $s[31] = $s11 >> 17;
- return self::intArrayToString($s);
- }
-
- /**
- * @param string $s
- * @return string
- */
- public static function sc25519_sq($s)
- {
- return self::sc25519_mul($s, $s);
- }
-
- /**
- * @param string $s
- * @param int $n
- * @param string $a
- * @return string
- */
- public static function sc25519_sqmul($s, $n, $a)
- {
- for ($i = 0; $i < $n; ++$i) {
- $s = self::sc25519_sq($s);
- }
- return self::sc25519_mul($s, $a);
- }
-
- /**
- * @param string $s
- * @return string
- */
- public static function sc25519_invert($s)
- {
- $_10 = self::sc25519_sq($s);
- $_11 = self::sc25519_mul($s, $_10);
- $_100 = self::sc25519_mul($s, $_11);
- $_1000 = self::sc25519_sq($_100);
- $_1010 = self::sc25519_mul($_10, $_1000);
- $_1011 = self::sc25519_mul($s, $_1010);
- $_10000 = self::sc25519_sq($_1000);
- $_10110 = self::sc25519_sq($_1011);
- $_100000 = self::sc25519_mul($_1010, $_10110);
- $_100110 = self::sc25519_mul($_10000, $_10110);
- $_1000000 = self::sc25519_sq($_100000);
- $_1010000 = self::sc25519_mul($_10000, $_1000000);
- $_1010011 = self::sc25519_mul($_11, $_1010000);
- $_1100011 = self::sc25519_mul($_10000, $_1010011);
- $_1100111 = self::sc25519_mul($_100, $_1100011);
- $_1101011 = self::sc25519_mul($_100, $_1100111);
- $_10010011 = self::sc25519_mul($_1000000, $_1010011);
- $_10010111 = self::sc25519_mul($_100, $_10010011);
- $_10111101 = self::sc25519_mul($_100110, $_10010111);
- $_11010011 = self::sc25519_mul($_10110, $_10111101);
- $_11100111 = self::sc25519_mul($_1010000, $_10010111);
- $_11101011 = self::sc25519_mul($_100, $_11100111);
- $_11110101 = self::sc25519_mul($_1010, $_11101011);
-
- $recip = self::sc25519_mul($_1011, $_11110101);
- $recip = self::sc25519_sqmul($recip, 126, $_1010011);
- $recip = self::sc25519_sqmul($recip, 9, $_10);
- $recip = self::sc25519_mul($recip, $_11110101);
- $recip = self::sc25519_sqmul($recip, 7, $_1100111);
- $recip = self::sc25519_sqmul($recip, 9, $_11110101);
- $recip = self::sc25519_sqmul($recip, 11, $_10111101);
- $recip = self::sc25519_sqmul($recip, 8, $_11100111);
- $recip = self::sc25519_sqmul($recip, 9, $_1101011);
- $recip = self::sc25519_sqmul($recip, 6, $_1011);
- $recip = self::sc25519_sqmul($recip, 14, $_10010011);
- $recip = self::sc25519_sqmul($recip, 10, $_1100011);
- $recip = self::sc25519_sqmul($recip, 9, $_10010111);
- $recip = self::sc25519_sqmul($recip, 10, $_11110101);
- $recip = self::sc25519_sqmul($recip, 8, $_11010011);
- return self::sc25519_sqmul($recip, 8, $_11101011);
- }
-
- /**
- * @param string $s
- * @return string
- */
- public static function clamp($s)
- {
- $s_ = self::stringToIntArray($s);
- $s_[0] &= 248;
- $s_[31] |= 64;
- $s_[31] &= 128;
- return self::intArrayToString($s_);
- }
-}
+<?php
+
+if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
+ return;
+}
+
+/**
+ * Class ParagonIE_Sodium_Core_Curve25519
+ *
+ * Implements Curve25519 core functions
+ *
+ * Based on the ref10 curve25519 code provided by libsodium
+ *
+ * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
+ */
+abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Curve25519_H
+{
+ /**
+ * Get a field element of size 10 with a value of 0
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_0()
+ {
+ return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ );
+ }
+
+ /**
+ * Get a field element of size 10 with a value of 1
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_1()
+ {
+ return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ );
+ }
+
+ /**
+ * Add two field elements.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ * @psalm-suppress MixedAssignment
+ * @psalm-suppress MixedOperand
+ */
+ public static function fe_add(
+ ParagonIE_Sodium_Core_Curve25519_Fe $f,
+ ParagonIE_Sodium_Core_Curve25519_Fe $g
+ ) {
+ /** @var array<int, int> $arr */
+ $arr = array();
+ for ($i = 0; $i < 10; ++$i) {
+ $arr[$i] = (int) ($f[$i] + $g[$i]);
+ }
+ return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr);
+ }
+
+ /**
+ * Constant-time conditional move.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
+ * @param int $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ * @psalm-suppress MixedAssignment
+ */
+ public static function fe_cmov(
+ ParagonIE_Sodium_Core_Curve25519_Fe $f,
+ ParagonIE_Sodium_Core_Curve25519_Fe $g,
+ $b = 0
+ ) {
+ /** @var array<int, int> $h */
+ $h = array();
+ $b *= -1;
+ for ($i = 0; $i < 10; ++$i) {
+ $x = (($f[$i] ^ $g[$i]) & $b);
+ $h[$i] = ($f[$i]) ^ $x;
+ }
+ return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
+ }
+
+ /**
+ * Create a copy of a field element.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ $h = clone $f;
+ return $h;
+ }
+
+ /**
+ * Give: 32-byte string.
+ * Receive: A field element object to use for internal calculations.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param string $s
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ * @throws RangeException
+ * @throws TypeError
+ */
+ public static function fe_frombytes($s)
+ {
+ if (self::strlen($s) !== 32) {
+ throw new RangeException('Expected a 32-byte string.');
+ }
+ $h0 = self::load_4($s);
+ $h1 = self::load_3(self::substr($s, 4, 3)) << 6;
+ $h2 = self::load_3(self::substr($s, 7, 3)) << 5;
+ $h3 = self::load_3(self::substr($s, 10, 3)) << 3;
+ $h4 = self::load_3(self::substr($s, 13, 3)) << 2;
+ $h5 = self::load_4(self::substr($s, 16, 4));
+ $h6 = self::load_3(self::substr($s, 20, 3)) << 7;
+ $h7 = self::load_3(self::substr($s, 23, 3)) << 5;
+ $h8 = self::load_3(self::substr($s, 26, 3)) << 4;
+ $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2;
+
+ $carry9 = ($h9 + (1 << 24)) >> 25;
+ $h0 += self::mul($carry9, 19, 5);
+ $h9 -= $carry9 << 25;
+ $carry1 = ($h1 + (1 << 24)) >> 25;
+ $h2 += $carry1;
+ $h1 -= $carry1 << 25;
+ $carry3 = ($h3 + (1 << 24)) >> 25;
+ $h4 += $carry3;
+ $h3 -= $carry3 << 25;
+ $carry5 = ($h5 + (1 << 24)) >> 25;
+ $h6 += $carry5;
+ $h5 -= $carry5 << 25;
+ $carry7 = ($h7 + (1 << 24)) >> 25;
+ $h8 += $carry7;
+ $h7 -= $carry7 << 25;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+ $carry2 = ($h2 + (1 << 25)) >> 26;
+ $h3 += $carry2;
+ $h2 -= $carry2 << 26;
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+ $carry6 = ($h6 + (1 << 25)) >> 26;
+ $h7 += $carry6;
+ $h6 -= $carry6 << 26;
+ $carry8 = ($h8 + (1 << 25)) >> 26;
+ $h9 += $carry8;
+ $h8 -= $carry8 << 26;
+
+ return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(
+ (int) $h0,
+ (int) $h1,
+ (int) $h2,
+ (int) $h3,
+ (int) $h4,
+ (int) $h5,
+ (int) $h6,
+ (int) $h7,
+ (int) $h8,
+ (int) $h9
+ )
+ );
+ }
+
+ /**
+ * Convert a field element to a byte string.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $h
+ * @return string
+ */
+ public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h)
+ {
+ $h0 = (int) $h[0];
+ $h1 = (int) $h[1];
+ $h2 = (int) $h[2];
+ $h3 = (int) $h[3];
+ $h4 = (int) $h[4];
+ $h5 = (int) $h[5];
+ $h6 = (int) $h[6];
+ $h7 = (int) $h[7];
+ $h8 = (int) $h[8];
+ $h9 = (int) $h[9];
+
+ $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
+ $q = ($h0 + $q) >> 26;
+ $q = ($h1 + $q) >> 25;
+ $q = ($h2 + $q) >> 26;
+ $q = ($h3 + $q) >> 25;
+ $q = ($h4 + $q) >> 26;
+ $q = ($h5 + $q) >> 25;
+ $q = ($h6 + $q) >> 26;
+ $q = ($h7 + $q) >> 25;
+ $q = ($h8 + $q) >> 26;
+ $q = ($h9 + $q) >> 25;
+
+ $h0 += self::mul($q, 19, 5);
+
+ $carry0 = $h0 >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+ $carry1 = $h1 >> 25;
+ $h2 += $carry1;
+ $h1 -= $carry1 << 25;
+ $carry2 = $h2 >> 26;
+ $h3 += $carry2;
+ $h2 -= $carry2 << 26;
+ $carry3 = $h3 >> 25;
+ $h4 += $carry3;
+ $h3 -= $carry3 << 25;
+ $carry4 = $h4 >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+ $carry5 = $h5 >> 25;
+ $h6 += $carry5;
+ $h5 -= $carry5 << 25;
+ $carry6 = $h6 >> 26;
+ $h7 += $carry6;
+ $h6 -= $carry6 << 26;
+ $carry7 = $h7 >> 25;
+ $h8 += $carry7;
+ $h7 -= $carry7 << 25;
+ $carry8 = $h8 >> 26;
+ $h9 += $carry8;
+ $h8 -= $carry8 << 26;
+ $carry9 = $h9 >> 25;
+ $h9 -= $carry9 << 25;
+
+ /**
+ * @var array<int, int>
+ */
+ $s = array(
+ (int) (($h0 >> 0) & 0xff),
+ (int) (($h0 >> 8) & 0xff),
+ (int) (($h0 >> 16) & 0xff),
+ (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
+ (int) (($h1 >> 6) & 0xff),
+ (int) (($h1 >> 14) & 0xff),
+ (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
+ (int) (($h2 >> 5) & 0xff),
+ (int) (($h2 >> 13) & 0xff),
+ (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
+ (int) (($h3 >> 3) & 0xff),
+ (int) (($h3 >> 11) & 0xff),
+ (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
+ (int) (($h4 >> 2) & 0xff),
+ (int) (($h4 >> 10) & 0xff),
+ (int) (($h4 >> 18) & 0xff),
+ (int) (($h5 >> 0) & 0xff),
+ (int) (($h5 >> 8) & 0xff),
+ (int) (($h5 >> 16) & 0xff),
+ (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
+ (int) (($h6 >> 7) & 0xff),
+ (int) (($h6 >> 15) & 0xff),
+ (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
+ (int) (($h7 >> 5) & 0xff),
+ (int) (($h7 >> 13) & 0xff),
+ (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
+ (int) (($h8 >> 4) & 0xff),
+ (int) (($h8 >> 12) & 0xff),
+ (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
+ (int) (($h9 >> 2) & 0xff),
+ (int) (($h9 >> 10) & 0xff),
+ (int) (($h9 >> 18) & 0xff)
+ );
+ return self::intArrayToString($s);
+ }
+
+ /**
+ * Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return int
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ $str = self::fe_tobytes($f);
+ return (int) (self::chrToInt($str[0]) & 1);
+ }
+
+ /**
+ * Returns 0 if this field element results in all NUL bytes.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return bool
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ static $zero;
+ if ($zero === null) {
+ $zero = str_repeat("\x00", 32);
+ }
+ /** @var string $zero */
+ /** @var string $str */
+ $str = self::fe_tobytes($f);
+ return !self::verify_32($str, (string) $zero);
+ }
+
+ /**
+ * Multiply two field elements
+ *
+ * h = f * g
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @security Is multiplication a source of timing leaks? If so, can we do
+ * anything to prevent that from happening?
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_mul(
+ ParagonIE_Sodium_Core_Curve25519_Fe $f,
+ ParagonIE_Sodium_Core_Curve25519_Fe $g
+ ) {
+ // Ensure limbs aren't oversized.
+ $f = self::fe_normalize($f);
+ $g = self::fe_normalize($g);
+ $f0 = $f[0];
+ $f1 = $f[1];
+ $f2 = $f[2];
+ $f3 = $f[3];
+ $f4 = $f[4];
+ $f5 = $f[5];
+ $f6 = $f[6];
+ $f7 = $f[7];
+ $f8 = $f[8];
+ $f9 = $f[9];
+ $g0 = $g[0];
+ $g1 = $g[1];
+ $g2 = $g[2];
+ $g3 = $g[3];
+ $g4 = $g[4];
+ $g5 = $g[5];
+ $g6 = $g[6];
+ $g7 = $g[7];
+ $g8 = $g[8];
+ $g9 = $g[9];
+ $g1_19 = self::mul($g1, 19, 5);
+ $g2_19 = self::mul($g2, 19, 5);
+ $g3_19 = self::mul($g3, 19, 5);
+ $g4_19 = self::mul($g4, 19, 5);
+ $g5_19 = self::mul($g5, 19, 5);
+ $g6_19 = self::mul($g6, 19, 5);
+ $g7_19 = self::mul($g7, 19, 5);
+ $g8_19 = self::mul($g8, 19, 5);
+ $g9_19 = self::mul($g9, 19, 5);
+ $f1_2 = $f1 << 1;
+ $f3_2 = $f3 << 1;
+ $f5_2 = $f5 << 1;
+ $f7_2 = $f7 << 1;
+ $f9_2 = $f9 << 1;
+ $f0g0 = self::mul($f0, $g0, 26);
+ $f0g1 = self::mul($f0, $g1, 25);
+ $f0g2 = self::mul($f0, $g2, 26);
+ $f0g3 = self::mul($f0, $g3, 25);
+ $f0g4 = self::mul($f0, $g4, 26);
+ $f0g5 = self::mul($f0, $g5, 25);
+ $f0g6 = self::mul($f0, $g6, 26);
+ $f0g7 = self::mul($f0, $g7, 25);
+ $f0g8 = self::mul($f0, $g8, 26);
+ $f0g9 = self::mul($f0, $g9, 26);
+ $f1g0 = self::mul($f1, $g0, 26);
+ $f1g1_2 = self::mul($f1_2, $g1, 25);
+ $f1g2 = self::mul($f1, $g2, 26);
+ $f1g3_2 = self::mul($f1_2, $g3, 25);
+ $f1g4 = self::mul($f1, $g4, 26);
+ $f1g5_2 = self::mul($f1_2, $g5, 25);
+ $f1g6 = self::mul($f1, $g6, 26);
+ $f1g7_2 = self::mul($f1_2, $g7, 25);
+ $f1g8 = self::mul($f1, $g8, 26);
+ $f1g9_38 = self::mul($g9_19, $f1_2, 26);
+ $f2g0 = self::mul($f2, $g0, 26);
+ $f2g1 = self::mul($f2, $g1, 25);
+ $f2g2 = self::mul($f2, $g2, 26);
+ $f2g3 = self::mul($f2, $g3, 25);
+ $f2g4 = self::mul($f2, $g4, 26);
+ $f2g5 = self::mul($f2, $g5, 25);
+ $f2g6 = self::mul($f2, $g6, 26);
+ $f2g7 = self::mul($f2, $g7, 25);
+ $f2g8_19 = self::mul($g8_19, $f2, 26);
+ $f2g9_19 = self::mul($g9_19, $f2, 26);
+ $f3g0 = self::mul($f3, $g0, 26);
+ $f3g1_2 = self::mul($f3_2, $g1, 25);
+ $f3g2 = self::mul($f3, $g2, 26);
+ $f3g3_2 = self::mul($f3_2, $g3, 25);
+ $f3g4 = self::mul($f3, $g4, 26);
+ $f3g5_2 = self::mul($f3_2, $g5, 25);
+ $f3g6 = self::mul($f3, $g6, 26);
+ $f3g7_38 = self::mul($g7_19, $f3_2, 26);
+ $f3g8_19 = self::mul($g8_19, $f3, 25);
+ $f3g9_38 = self::mul($g9_19, $f3_2, 26);
+ $f4g0 = self::mul($f4, $g0, 26);
+ $f4g1 = self::mul($f4, $g1, 25);
+ $f4g2 = self::mul($f4, $g2, 26);
+ $f4g3 = self::mul($f4, $g3, 25);
+ $f4g4 = self::mul($f4, $g4, 26);
+ $f4g5 = self::mul($f4, $g5, 25);
+ $f4g6_19 = self::mul($g6_19, $f4, 26);
+ $f4g7_19 = self::mul($g7_19, $f4, 26);
+ $f4g8_19 = self::mul($g8_19, $f4, 26);
+ $f4g9_19 = self::mul($g9_19, $f4, 26);
+ $f5g0 = self::mul($f5, $g0, 26);
+ $f5g1_2 = self::mul($f5_2, $g1, 25);
+ $f5g2 = self::mul($f5, $g2, 26);
+ $f5g3_2 = self::mul($f5_2, $g3, 25);
+ $f5g4 = self::mul($f5, $g4, 26);
+ $f5g5_38 = self::mul($g5_19, $f5_2, 26);
+ $f5g6_19 = self::mul($g6_19, $f5, 25);
+ $f5g7_38 = self::mul($g7_19, $f5_2, 26);
+ $f5g8_19 = self::mul($g8_19, $f5, 25);
+ $f5g9_38 = self::mul($g9_19, $f5_2, 26);
+ $f6g0 = self::mul($f6, $g0, 26);
+ $f6g1 = self::mul($f6, $g1, 25);
+ $f6g2 = self::mul($f6, $g2, 26);
+ $f6g3 = self::mul($f6, $g3, 25);
+ $f6g4_19 = self::mul($g4_19, $f6, 26);
+ $f6g5_19 = self::mul($g5_19, $f6, 26);
+ $f6g6_19 = self::mul($g6_19, $f6, 26);
+ $f6g7_19 = self::mul($g7_19, $f6, 26);
+ $f6g8_19 = self::mul($g8_19, $f6, 26);
+ $f6g9_19 = self::mul($g9_19, $f6, 26);
+ $f7g0 = self::mul($f7, $g0, 26);
+ $f7g1_2 = self::mul($f7_2, $g1, 25);
+ $f7g2 = self::mul($f7, $g2, 26);
+ $f7g3_38 = self::mul($g3_19, $f7_2, 26);
+ $f7g4_19 = self::mul($g4_19, $f7, 26);
+ $f7g5_38 = self::mul($g5_19, $f7_2, 26);
+ $f7g6_19 = self::mul($g6_19, $f7, 25);
+ $f7g7_38 = self::mul($g7_19, $f7_2, 26);
+ $f7g8_19 = self::mul($g8_19, $f7, 25);
+ $f7g9_38 = self::mul($g9_19,$f7_2, 26);
+ $f8g0 = self::mul($f8, $g0, 26);
+ $f8g1 = self::mul($f8, $g1, 25);
+ $f8g2_19 = self::mul($g2_19, $f8, 26);
+ $f8g3_19 = self::mul($g3_19, $f8, 26);
+ $f8g4_19 = self::mul($g4_19, $f8, 26);
+ $f8g5_19 = self::mul($g5_19, $f8, 26);
+ $f8g6_19 = self::mul($g6_19, $f8, 26);
+ $f8g7_19 = self::mul($g7_19, $f8, 26);
+ $f8g8_19 = self::mul($g8_19, $f8, 26);
+ $f8g9_19 = self::mul($g9_19, $f8, 26);
+ $f9g0 = self::mul($f9, $g0, 26);
+ $f9g1_38 = self::mul($g1_19, $f9_2, 26);
+ $f9g2_19 = self::mul($g2_19, $f9, 25);
+ $f9g3_38 = self::mul($g3_19, $f9_2, 26);
+ $f9g4_19 = self::mul($g4_19, $f9, 25);
+ $f9g5_38 = self::mul($g5_19, $f9_2, 26);
+ $f9g6_19 = self::mul($g6_19, $f9, 25);
+ $f9g7_38 = self::mul($g7_19, $f9_2, 26);
+ $f9g8_19 = self::mul($g8_19, $f9, 25);
+ $f9g9_38 = self::mul($g9_19, $f9_2, 26);
+
+ $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
+ $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
+ $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
+ $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
+ $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
+ $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
+ $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38;
+ $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19;
+ $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38;
+ $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+
+ $carry1 = ($h1 + (1 << 24)) >> 25;
+ $h2 += $carry1;
+ $h1 -= $carry1 << 25;
+ $carry5 = ($h5 + (1 << 24)) >> 25;
+ $h6 += $carry5;
+ $h5 -= $carry5 << 25;
+
+ $carry2 = ($h2 + (1 << 25)) >> 26;
+ $h3 += $carry2;
+ $h2 -= $carry2 << 26;
+ $carry6 = ($h6 + (1 << 25)) >> 26;
+ $h7 += $carry6;
+ $h6 -= $carry6 << 26;
+
+ $carry3 = ($h3 + (1 << 24)) >> 25;
+ $h4 += $carry3;
+ $h3 -= $carry3 << 25;
+ $carry7 = ($h7 + (1 << 24)) >> 25;
+ $h8 += $carry7;
+ $h7 -= $carry7 << 25;
+
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+ $carry8 = ($h8 + (1 << 25)) >> 26;
+ $h9 += $carry8;
+ $h8 -= $carry8 << 26;
+
+ $carry9 = ($h9 + (1 << 24)) >> 25;
+ $h0 += self::mul($carry9, 19, 5);
+ $h9 -= $carry9 << 25;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+
+ return self::fe_normalize(
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(
+ (int) $h0,
+ (int) $h1,
+ (int) $h2,
+ (int) $h3,
+ (int) $h4,
+ (int) $h5,
+ (int) $h6,
+ (int) $h7,
+ (int) $h8,
+ (int) $h9
+ )
+ )
+ );
+ }
+
+ /**
+ * Get the negative values for each piece of the field element.
+ *
+ * h = -f
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ * @psalm-suppress MixedAssignment
+ */
+ public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ $h = new ParagonIE_Sodium_Core_Curve25519_Fe();
+ for ($i = 0; $i < 10; ++$i) {
+ $h[$i] = -$f[$i];
+ }
+ return self::fe_normalize($h);
+ }
+
+ /**
+ * Square a field element
+ *
+ * h = f * f
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ $f = self::fe_normalize($f);
+ $f0 = (int) $f[0];
+ $f1 = (int) $f[1];
+ $f2 = (int) $f[2];
+ $f3 = (int) $f[3];
+ $f4 = (int) $f[4];
+ $f5 = (int) $f[5];
+ $f6 = (int) $f[6];
+ $f7 = (int) $f[7];
+ $f8 = (int) $f[8];
+ $f9 = (int) $f[9];
+
+ $f0_2 = $f0 << 1;
+ $f1_2 = $f1 << 1;
+ $f2_2 = $f2 << 1;
+ $f3_2 = $f3 << 1;
+ $f4_2 = $f4 << 1;
+ $f5_2 = $f5 << 1;
+ $f6_2 = $f6 << 1;
+ $f7_2 = $f7 << 1;
+ $f5_38 = self::mul($f5, 38, 6);
+ $f6_19 = self::mul($f6, 19, 5);
+ $f7_38 = self::mul($f7, 38, 6);
+ $f8_19 = self::mul($f8, 19, 5);
+ $f9_38 = self::mul($f9, 38, 6);
+ $f0f0 = self::mul($f0, $f0, 26);
+ $f0f1_2 = self::mul($f0_2, $f1, 26);
+ $f0f2_2 = self::mul($f0_2, $f2, 26);
+ $f0f3_2 = self::mul($f0_2, $f3, 26);
+ $f0f4_2 = self::mul($f0_2, $f4, 26);
+ $f0f5_2 = self::mul($f0_2, $f5, 26);
+ $f0f6_2 = self::mul($f0_2, $f6, 26);
+ $f0f7_2 = self::mul($f0_2, $f7, 26);
+ $f0f8_2 = self::mul($f0_2, $f8, 26);
+ $f0f9_2 = self::mul($f0_2, $f9, 26);
+ $f1f1_2 = self::mul($f1_2, $f1, 26);
+ $f1f2_2 = self::mul($f1_2, $f2, 26);
+ $f1f3_4 = self::mul($f1_2, $f3_2, 26);
+ $f1f4_2 = self::mul($f1_2, $f4, 26);
+ $f1f5_4 = self::mul($f1_2, $f5_2, 26);
+ $f1f6_2 = self::mul($f1_2, $f6, 26);
+ $f1f7_4 = self::mul($f1_2, $f7_2, 26);
+ $f1f8_2 = self::mul($f1_2, $f8, 26);
+ $f1f9_76 = self::mul($f9_38, $f1_2, 27);
+ $f2f2 = self::mul($f2, $f2, 27);
+ $f2f3_2 = self::mul($f2_2, $f3, 27);
+ $f2f4_2 = self::mul($f2_2, $f4, 27);
+ $f2f5_2 = self::mul($f2_2, $f5, 27);
+ $f2f6_2 = self::mul($f2_2, $f6, 27);
+ $f2f7_2 = self::mul($f2_2, $f7, 27);
+ $f2f8_38 = self::mul($f8_19, $f2_2, 27);
+ $f2f9_38 = self::mul($f9_38, $f2, 26);
+ $f3f3_2 = self::mul($f3_2, $f3, 26);
+ $f3f4_2 = self::mul($f3_2, $f4, 26);
+ $f3f5_4 = self::mul($f3_2, $f5_2, 26);
+ $f3f6_2 = self::mul($f3_2, $f6, 26);
+ $f3f7_76 = self::mul($f7_38, $f3_2, 26);
+ $f3f8_38 = self::mul($f8_19, $f3_2, 26);
+ $f3f9_76 = self::mul($f9_38, $f3_2, 26);
+ $f4f4 = self::mul($f4, $f4, 26);
+ $f4f5_2 = self::mul($f4_2, $f5, 26);
+ $f4f6_38 = self::mul($f6_19, $f4_2, 27);
+ $f4f7_38 = self::mul($f7_38, $f4, 26);
+ $f4f8_38 = self::mul($f8_19, $f4_2, 27);
+ $f4f9_38 = self::mul($f9_38, $f4, 26);
+ $f5f5_38 = self::mul($f5_38, $f5, 26);
+ $f5f6_38 = self::mul($f6_19, $f5_2, 26);
+ $f5f7_76 = self::mul($f7_38, $f5_2, 26);
+ $f5f8_38 = self::mul($f8_19, $f5_2, 26);
+ $f5f9_76 = self::mul($f9_38, $f5_2, 26);
+ $f6f6_19 = self::mul($f6_19, $f6, 26);
+ $f6f7_38 = self::mul($f7_38, $f6, 26);
+ $f6f8_38 = self::mul($f8_19, $f6_2, 27);
+ $f6f9_38 = self::mul($f9_38, $f6, 26);
+ $f7f7_38 = self::mul($f7_38, $f7, 26);
+ $f7f8_38 = self::mul($f8_19, $f7_2, 26);
+ $f7f9_76 = self::mul($f9_38, $f7_2, 26);
+ $f8f8_19 = self::mul($f8_19, $f8, 26);
+ $f8f9_38 = self::mul($f9_38, $f8, 26);
+ $f9f9_38 = self::mul($f9_38, $f9, 26);
+ $h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38;
+ $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
+ $h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19;
+ $h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38;
+ $h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38;
+ $h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38;
+ $h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19;
+ $h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38;
+ $h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38;
+ $h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+
+ $carry1 = ($h1 + (1 << 24)) >> 25;
+ $h2 += $carry1;
+ $h1 -= $carry1 << 25;
+ $carry5 = ($h5 + (1 << 24)) >> 25;
+ $h6 += $carry5;
+ $h5 -= $carry5 << 25;
+
+ $carry2 = ($h2 + (1 << 25)) >> 26;
+ $h3 += $carry2;
+ $h2 -= $carry2 << 26;
+ $carry6 = ($h6 + (1 << 25)) >> 26;
+ $h7 += $carry6;
+ $h6 -= $carry6 << 26;
+
+ $carry3 = ($h3 + (1 << 24)) >> 25;
+ $h4 += $carry3;
+ $h3 -= $carry3 << 25;
+ $carry7 = ($h7 + (1 << 24)) >> 25;
+ $h8 += $carry7;
+ $h7 -= $carry7 << 25;
+
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+ $carry8 = ($h8 + (1 << 25)) >> 26;
+ $h9 += $carry8;
+ $h8 -= $carry8 << 26;
+
+ $carry9 = ($h9 + (1 << 24)) >> 25;
+ $h0 += self::mul($carry9, 19, 5);
+ $h9 -= $carry9 << 25;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+
+ return self::fe_normalize(
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(
+ (int) $h0,
+ (int) $h1,
+ (int) $h2,
+ (int) $h3,
+ (int) $h4,
+ (int) $h5,
+ (int) $h6,
+ (int) $h7,
+ (int) $h8,
+ (int) $h9
+ )
+ )
+ );
+ }
+
+
+ /**
+ * Square and double a field element
+ *
+ * h = 2 * f * f
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ $f = self::fe_normalize($f);
+ $f0 = (int) $f[0];
+ $f1 = (int) $f[1];
+ $f2 = (int) $f[2];
+ $f3 = (int) $f[3];
+ $f4 = (int) $f[4];
+ $f5 = (int) $f[5];
+ $f6 = (int) $f[6];
+ $f7 = (int) $f[7];
+ $f8 = (int) $f[8];
+ $f9 = (int) $f[9];
+
+ $f0_2 = $f0 << 1;
+ $f1_2 = $f1 << 1;
+ $f2_2 = $f2 << 1;
+ $f3_2 = $f3 << 1;
+ $f4_2 = $f4 << 1;
+ $f5_2 = $f5 << 1;
+ $f6_2 = $f6 << 1;
+ $f7_2 = $f7 << 1;
+ $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
+ $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
+ $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
+ $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
+ $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
+ $f0f0 = self::mul($f0, $f0, 24);
+ $f0f1_2 = self::mul($f0_2, $f1, 24);
+ $f0f2_2 = self::mul($f0_2, $f2, 24);
+ $f0f3_2 = self::mul($f0_2, $f3, 24);
+ $f0f4_2 = self::mul($f0_2, $f4, 24);
+ $f0f5_2 = self::mul($f0_2, $f5, 24);
+ $f0f6_2 = self::mul($f0_2, $f6, 24);
+ $f0f7_2 = self::mul($f0_2, $f7, 24);
+ $f0f8_2 = self::mul($f0_2, $f8, 24);
+ $f0f9_2 = self::mul($f0_2, $f9, 24);
+ $f1f1_2 = self::mul($f1_2, $f1, 24);
+ $f1f2_2 = self::mul($f1_2, $f2, 24);
+ $f1f3_4 = self::mul($f1_2, $f3_2, 24);
+ $f1f4_2 = self::mul($f1_2, $f4, 24);
+ $f1f5_4 = self::mul($f1_2, $f5_2, 24);
+ $f1f6_2 = self::mul($f1_2, $f6, 24);
+ $f1f7_4 = self::mul($f1_2, $f7_2, 24);
+ $f1f8_2 = self::mul($f1_2, $f8, 24);
+ $f1f9_76 = self::mul($f9_38, $f1_2, 24);
+ $f2f2 = self::mul($f2, $f2, 24);
+ $f2f3_2 = self::mul($f2_2, $f3, 24);
+ $f2f4_2 = self::mul($f2_2, $f4, 24);
+ $f2f5_2 = self::mul($f2_2, $f5, 24);
+ $f2f6_2 = self::mul($f2_2, $f6, 24);
+ $f2f7_2 = self::mul($f2_2, $f7, 24);
+ $f2f8_38 = self::mul($f8_19, $f2_2, 25);
+ $f2f9_38 = self::mul($f9_38, $f2, 24);
+ $f3f3_2 = self::mul($f3_2, $f3, 24);
+ $f3f4_2 = self::mul($f3_2, $f4, 24);
+ $f3f5_4 = self::mul($f3_2, $f5_2, 24);
+ $f3f6_2 = self::mul($f3_2, $f6, 24);
+ $f3f7_76 = self::mul($f7_38, $f3_2, 24);
+ $f3f8_38 = self::mul($f8_19, $f3_2, 24);
+ $f3f9_76 = self::mul($f9_38, $f3_2, 24);
+ $f4f4 = self::mul($f4, $f4, 24);
+ $f4f5_2 = self::mul($f4_2, $f5, 24);
+ $f4f6_38 = self::mul($f6_19, $f4_2, 25);
+ $f4f7_38 = self::mul($f7_38, $f4, 24);
+ $f4f8_38 = self::mul($f8_19, $f4_2, 25);
+ $f4f9_38 = self::mul($f9_38, $f4, 24);
+ $f5f5_38 = self::mul($f5_38, $f5, 24);
+ $f5f6_38 = self::mul($f6_19, $f5_2, 24);
+ $f5f7_76 = self::mul($f7_38, $f5_2, 24);
+ $f5f8_38 = self::mul($f8_19, $f5_2, 24);
+ $f5f9_76 = self::mul($f9_38, $f5_2, 24);
+ $f6f6_19 = self::mul($f6_19, $f6, 24);
+ $f6f7_38 = self::mul($f7_38, $f6, 24);
+ $f6f8_38 = self::mul($f8_19, $f6_2, 25);
+ $f6f9_38 = self::mul($f9_38, $f6, 24);
+ $f7f7_38 = self::mul($f7_38, $f7, 24);
+ $f7f8_38 = self::mul($f8_19, $f7_2, 24);
+ $f7f9_76 = self::mul($f9_38, $f7_2, 24);
+ $f8f8_19 = self::mul($f8_19, $f8, 24);
+ $f8f9_38 = self::mul($f9_38, $f8, 24);
+ $f9f9_38 = self::mul($f9_38, $f9, 24);
+
+ $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1;
+ $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1;
+ $h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1;
+ $h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1;
+ $h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1;
+ $h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38) << 1;
+ $h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19) << 1;
+ $h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38) << 1;
+ $h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38) << 1;
+ $h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2) << 1;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+
+ $carry1 = ($h1 + (1 << 24)) >> 25;
+ $h2 += $carry1;
+ $h1 -= $carry1 << 25;
+ $carry5 = ($h5 + (1 << 24)) >> 25;
+ $h6 += $carry5;
+ $h5 -= $carry5 << 25;
+
+ $carry2 = ($h2 + (1 << 25)) >> 26;
+ $h3 += $carry2;
+ $h2 -= $carry2 << 26;
+ $carry6 = ($h6 + (1 << 25)) >> 26;
+ $h7 += $carry6;
+ $h6 -= $carry6 << 26;
+
+ $carry3 = ($h3 + (1 << 24)) >> 25;
+ $h4 += $carry3;
+ $h3 -= $carry3 << 25;
+ $carry7 = ($h7 + (1 << 24)) >> 25;
+ $h8 += $carry7;
+ $h7 -= $carry7 << 25;
+
+ $carry4 = ($h4 + (1 << 25)) >> 26;
+ $h5 += $carry4;
+ $h4 -= $carry4 << 26;
+ $carry8 = ($h8 + (1 << 25)) >> 26;
+ $h9 += $carry8;
+ $h8 -= $carry8 << 26;
+
+ $carry9 = ($h9 + (1 << 24)) >> 25;
+ $h0 += self::mul($carry9, 19, 5);
+ $h9 -= $carry9 << 25;
+
+ $carry0 = ($h0 + (1 << 25)) >> 26;
+ $h1 += $carry0;
+ $h0 -= $carry0 << 26;
+
+ return self::fe_normalize(
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(
+ (int) $h0,
+ (int) $h1,
+ (int) $h2,
+ (int) $h3,
+ (int) $h4,
+ (int) $h5,
+ (int) $h6,
+ (int) $h7,
+ (int) $h8,
+ (int) $h9
+ )
+ )
+ );
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z)
+ {
+ $z = clone $Z;
+ $t0 = self::fe_sq($z);
+ $t1 = self::fe_sq($t0);
+ $t1 = self::fe_sq($t1);
+ $t1 = self::fe_mul($z, $t1);
+ $t0 = self::fe_mul($t0, $t1);
+ $t2 = self::fe_sq($t0);
+ $t1 = self::fe_mul($t1, $t2);
+ $t2 = self::fe_sq($t1);
+ for ($i = 1; $i < 5; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+ $t1 = self::fe_mul($t2, $t1);
+ $t2 = self::fe_sq($t1);
+ for ($i = 1; $i < 10; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+ $t2 = self::fe_mul($t2, $t1);
+ $t3 = self::fe_sq($t2);
+ for ($i = 1; $i < 20; ++$i) {
+ $t3 = self::fe_sq($t3);
+ }
+ $t2 = self::fe_mul($t3, $t2);
+ $t2 = self::fe_sq($t2);
+ for ($i = 1; $i < 10; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+ $t1 = self::fe_mul($t2, $t1);
+ $t2 = self::fe_sq($t1);
+ for ($i = 1; $i < 50; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+ $t2 = self::fe_mul($t2, $t1);
+ $t3 = self::fe_sq($t2);
+ for ($i = 1; $i < 100; ++$i) {
+ $t3 = self::fe_sq($t3);
+ }
+ $t2 = self::fe_mul($t3, $t2);
+ $t2 = self::fe_sq($t2);
+ for ($i = 1; $i < 50; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+ $t1 = self::fe_mul($t2, $t1);
+ $t1 = self::fe_sq($t1);
+ for ($i = 1; $i < 5; ++$i) {
+ $t1 = self::fe_sq($t1);
+ }
+ return self::fe_mul($t1, $t0);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $z
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z)
+ {
+ $z = self::fe_normalize($z);
+ # fe_sq(t0, z);
+ # fe_sq(t1, t0);
+ # fe_sq(t1, t1);
+ # fe_mul(t1, z, t1);
+ # fe_mul(t0, t0, t1);
+ # fe_sq(t0, t0);
+ # fe_mul(t0, t1, t0);
+ # fe_sq(t1, t0);
+ $t0 = self::fe_sq($z);
+ $t1 = self::fe_sq($t0);
+ $t1 = self::fe_sq($t1);
+ $t1 = self::fe_mul($z, $t1);
+ $t0 = self::fe_mul($t0, $t1);
+ $t0 = self::fe_sq($t0);
+ $t0 = self::fe_mul($t1, $t0);
+ $t1 = self::fe_sq($t0);
+
+ # for (i = 1; i < 5; ++i) {
+ # fe_sq(t1, t1);
+ # }
+ for ($i = 1; $i < 5; ++$i) {
+ $t1 = self::fe_sq($t1);
+ }
+
+ # fe_mul(t0, t1, t0);
+ # fe_sq(t1, t0);
+ $t0 = self::fe_mul($t1, $t0);
+ $t1 = self::fe_sq($t0);
+
+ # for (i = 1; i < 10; ++i) {
+ # fe_sq(t1, t1);
+ # }
+ for ($i = 1; $i < 10; ++$i) {
+ $t1 = self::fe_sq($t1);
+ }
+
+ # fe_mul(t1, t1, t0);
+ # fe_sq(t2, t1);
+ $t1 = self::fe_mul($t1, $t0);
+ $t2 = self::fe_sq($t1);
+
+ # for (i = 1; i < 20; ++i) {
+ # fe_sq(t2, t2);
+ # }
+ for ($i = 1; $i < 20; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+
+ # fe_mul(t1, t2, t1);
+ # fe_sq(t1, t1);
+ $t1 = self::fe_mul($t2, $t1);
+ $t1 = self::fe_sq($t1);
+
+ # for (i = 1; i < 10; ++i) {
+ # fe_sq(t1, t1);
+ # }
+ for ($i = 1; $i < 10; ++$i) {
+ $t1 = self::fe_sq($t1);
+ }
+
+ # fe_mul(t0, t1, t0);
+ # fe_sq(t1, t0);
+ $t0 = self::fe_mul($t1, $t0);
+ $t1 = self::fe_sq($t0);
+
+ # for (i = 1; i < 50; ++i) {
+ # fe_sq(t1, t1);
+ # }
+ for ($i = 1; $i < 50; ++$i) {
+ $t1 = self::fe_sq($t1);
+ }
+
+ # fe_mul(t1, t1, t0);
+ # fe_sq(t2, t1);
+ $t1 = self::fe_mul($t1, $t0);
+ $t2 = self::fe_sq($t1);
+
+ # for (i = 1; i < 100; ++i) {
+ # fe_sq(t2, t2);
+ # }
+ for ($i = 1; $i < 100; ++$i) {
+ $t2 = self::fe_sq($t2);
+ }
+
+ # fe_mul(t1, t2, t1);
+ # fe_sq(t1, t1);
+ $t1 = self::fe_mul($t2, $t1);
+ $t1 = self::fe_sq($t1);
+
+ # for (i = 1; i < 50; ++i) {
+ # fe_sq(t1, t1);
+ # }
+ for ($i = 1; $i < 50; ++$i) {
+ $t1 = self::fe_sq($t1);
+ }
+
+ # fe_mul(t0, t1, t0);
+ # fe_sq(t0, t0);
+ # fe_sq(t0, t0);
+ # fe_mul(out, t0, z);
+ $t0 = self::fe_mul($t1, $t0);
+ $t0 = self::fe_sq($t0);
+ $t0 = self::fe_sq($t0);
+ return self::fe_mul($t0, $z);
+ }
+
+ /**
+ * Subtract two field elements.
+ *
+ * h = f - g
+ *
+ * Preconditions:
+ * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ *
+ * Postconditions:
+ * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ * @psalm-suppress MixedOperand
+ */
+ public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g)
+ {
+ return self::fe_normalize(
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
+ array(
+ (int) ($f[0] - $g[0]),
+ (int) ($f[1] - $g[1]),
+ (int) ($f[2] - $g[2]),
+ (int) ($f[3] - $g[3]),
+ (int) ($f[4] - $g[4]),
+ (int) ($f[5] - $g[5]),
+ (int) ($f[6] - $g[6]),
+ (int) ($f[7] - $g[7]),
+ (int) ($f[8] - $g[8]),
+ (int) ($f[9] - $g[9])
+ )
+ )
+ );
+ }
+
+ /**
+ * Add two group elements.
+ *
+ * r = p + q
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
+ */
+ public static function ge_add(
+ ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
+ ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
+ ) {
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
+ $r->X = self::fe_add($p->Y, $p->X);
+ $r->Y = self::fe_sub($p->Y, $p->X);
+ $r->Z = self::fe_mul($r->X, $q->YplusX);
+ $r->Y = self::fe_mul($r->Y, $q->YminusX);
+ $r->T = self::fe_mul($q->T2d, $p->T);
+ $r->X = self::fe_mul($p->Z, $q->Z);
+ $t0 = self::fe_add($r->X, $r->X);
+ $r->X = self::fe_sub($r->Z, $r->Y);
+ $r->Y = self::fe_add($r->Z, $r->Y);
+ $r->Z = self::fe_add($t0, $r->T);
+ $r->T = self::fe_sub($t0, $r->T);
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
+ * @param string $a
+ * @return array<int, mixed>
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function slide($a)
+ {
+ if (self::strlen($a) < 256) {
+ if (self::strlen($a) < 16) {
+ $a = str_pad($a, 256, '0', STR_PAD_RIGHT);
+ }
+ }
+ /** @var array<int, int> $r */
+ $r = array();
+
+ /** @var int $i */
+ for ($i = 0; $i < 256; ++$i) {
+ $r[$i] = (int) (
+ 1 & (
+ self::chrToInt($a[(int) ($i >> 3)])
+ >>
+ ($i & 7)
+ )
+ );
+ }
+
+ for ($i = 0;$i < 256;++$i) {
+ if ($r[$i]) {
+ for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
+ if ($r[$i + $b]) {
+ if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
+ $r[$i] += $r[$i + $b] << $b;
+ $r[$i + $b] = 0;
+ } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
+ $r[$i] -= $r[$i + $b] << $b;
+ for ($k = $i + $b; $k < 256; ++$k) {
+ if (!$r[$k]) {
+ $r[$k] = 1;
+ break;
+ }
+ $r[$k] = 0;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $s
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function ge_frombytes_negate_vartime($s)
+ {
+ static $d = null;
+ if (!$d) {
+ $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
+ }
+
+ # fe_frombytes(h->Y,s);
+ # fe_1(h->Z);
+ $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
+ self::fe_0(),
+ self::fe_frombytes($s),
+ self::fe_1()
+ );
+
+ # fe_sq(u,h->Y);
+ # fe_mul(v,u,d);
+ # fe_sub(u,u,h->Z); /* u = y^2-1 */
+ # fe_add(v,v,h->Z); /* v = dy^2+1 */
+ $u = self::fe_sq($h->Y);
+ /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
+ $v = self::fe_mul($u, $d);
+ $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */
+ $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
+
+ # fe_sq(v3,v);
+ # fe_mul(v3,v3,v); /* v3 = v^3 */
+ # fe_sq(h->X,v3);
+ # fe_mul(h->X,h->X,v);
+ # fe_mul(h->X,h->X,u); /* x = uv^7 */
+ $v3 = self::fe_sq($v);
+ $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
+ $h->X = self::fe_sq($v3);
+ $h->X = self::fe_mul($h->X, $v);
+ $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
+
+ # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+ # fe_mul(h->X,h->X,v3);
+ # fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
+ $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
+ $h->X = self::fe_mul($h->X, $v3);
+ $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
+
+ # fe_sq(vxx,h->X);
+ # fe_mul(vxx,vxx,v);
+ # fe_sub(check,vxx,u); /* vx^2-u */
+ $vxx = self::fe_sq($h->X);
+ $vxx = self::fe_mul($vxx, $v);
+ $check = self::fe_sub($vxx, $u); /* vx^2 - u */
+
+ # if (fe_isnonzero(check)) {
+ # fe_add(check,vxx,u); /* vx^2+u */
+ # if (fe_isnonzero(check)) {
+ # return -1;
+ # }
+ # fe_mul(h->X,h->X,sqrtm1);
+ # }
+ if (self::fe_isnonzero($check)) {
+ $check = self::fe_add($vxx, $u); /* vx^2 + u */
+ if (self::fe_isnonzero($check)) {
+ throw new RangeException('Internal check failed.');
+ }
+ $h->X = self::fe_mul(
+ $h->X,
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
+ );
+ }
+
+ # if (fe_isnegative(h->X) == (s[31] >> 7)) {
+ # fe_neg(h->X,h->X);
+ # }
+ $i = self::chrToInt($s[31]);
+ if (self::fe_isnegative($h->X) === ($i >> 7)) {
+ $h->X = self::fe_neg($h->X);
+ }
+
+ # fe_mul(h->T,h->X,h->Y);
+ $h->T = self::fe_mul($h->X, $h->Y);
+ return $h;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
+ */
+ public static function ge_madd(
+ ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
+ ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
+ ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
+ ) {
+ $r = clone $R;
+ $r->X = self::fe_add($p->Y, $p->X);
+ $r->Y = self::fe_sub($p->Y, $p->X);
+ $r->Z = self::fe_mul($r->X, $q->yplusx);
+ $r->Y = self::fe_mul($r->Y, $q->yminusx);
+ $r->T = self::fe_mul($q->xy2d, $p->T);
+ $t0 = self::fe_add(clone $p->Z, clone $p->Z);
+ $r->X = self::fe_sub($r->Z, $r->Y);
+ $r->Y = self::fe_add($r->Z, $r->Y);
+ $r->Z = self::fe_add($t0, $r->T);
+ $r->T = self::fe_sub($t0, $r->T);
+
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
+ */
+ public static function ge_msub(
+ ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
+ ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
+ ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
+ ) {
+ $r = clone $R;
+
+ $r->X = self::fe_add($p->Y, $p->X);
+ $r->Y = self::fe_sub($p->Y, $p->X);
+ $r->Z = self::fe_mul($r->X, $q->yminusx);
+ $r->Y = self::fe_mul($r->Y, $q->yplusx);
+ $r->T = self::fe_mul($q->xy2d, $p->T);
+ $t0 = self::fe_add($p->Z, $p->Z);
+ $r->X = self::fe_sub($r->Z, $r->Y);
+ $r->Y = self::fe_add($r->Z, $r->Y);
+ $r->Z = self::fe_sub($t0, $r->T);
+ $r->T = self::fe_add($t0, $r->T);
+
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
+ */
+ public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
+ {
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
+ $r->X = self::fe_mul($p->X, $p->T);
+ $r->Y = self::fe_mul($p->Y, $p->Z);
+ $r->Z = self::fe_mul($p->Z, $p->T);
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
+ */
+ public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
+ {
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
+ $r->X = self::fe_mul($p->X, $p->T);
+ $r->Y = self::fe_mul($p->Y, $p->Z);
+ $r->Z = self::fe_mul($p->Z, $p->T);
+ $r->T = self::fe_mul($p->X, $p->Y);
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
+ */
+ public static function ge_p2_0()
+ {
+ return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
+ self::fe_0(),
+ self::fe_1(),
+ self::fe_1()
+ );
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
+ */
+ public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p)
+ {
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
+
+ $r->X = self::fe_sq($p->X);
+ $r->Z = self::fe_sq($p->Y);
+ $r->T = self::fe_sq2($p->Z);
+ $r->Y = self::fe_add($p->X, $p->Y);
+ $t0 = self::fe_sq($r->Y);
+ $r->Y = self::fe_add($r->Z, $r->X);
+ $r->Z = self::fe_sub($r->Z, $r->X);
+ $r->X = self::fe_sub($t0, $r->Y);
+ $r->T = self::fe_sub($r->T, $r->Z);
+
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
+ */
+ public static function ge_p3_0()
+ {
+ return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
+ self::fe_0(),
+ self::fe_1(),
+ self::fe_1(),
+ self::fe_0()
+ );
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
+ */
+ public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
+ {
+ static $d2 = null;
+ if ($d2 === null) {
+ $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
+ }
+ /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
+ $r->YplusX = self::fe_add($p->Y, $p->X);
+ $r->YminusX = self::fe_sub($p->Y, $p->X);
+ $r->Z = self::fe_copy($p->Z);
+ $r->T2d = self::fe_mul($p->T, $d2);
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
+ */
+ public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
+ {
+ return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
+ self::fe_copy($p->X),
+ self::fe_copy($p->Y),
+ self::fe_copy($p->Z)
+ );
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
+ {
+ $recip = self::fe_invert($h->Z);
+ $x = self::fe_mul($h->X, $recip);
+ $y = self::fe_mul($h->Y, $recip);
+ $s = self::fe_tobytes($y);
+ $s[31] = self::intToChr(
+ self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
+ );
+ return $s;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
+ */
+ public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
+ {
+ $q = self::ge_p3_to_p2($p);
+ return self::ge_p2_dbl($q);
+ }
+
+ /**
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
+ */
+ public static function ge_precomp_0()
+ {
+ return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
+ self::fe_1(),
+ self::fe_1(),
+ self::fe_0()
+ );
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param int $b
+ * @param int $c
+ * @return int
+ */
+ public static function equal($b, $c)
+ {
+ return (int) ((($b ^ $c) - 1) >> 31) & 1;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param int|string $char
+ * @return int (1 = yes, 0 = no)
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function negative($char)
+ {
+ if (is_int($char)) {
+ return ($char >> 63) & 1;
+ }
+ $x = self::chrToInt(self::substr($char, 0, 1));
+ return (int) ($x >> 63);
+ }
+
+ /**
+ * Conditional move
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
+ * @param int $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
+ */
+ public static function cmov(
+ ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
+ ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
+ $b
+ ) {
+ if (!is_int($b)) {
+ throw new InvalidArgumentException('Expected an integer.');
+ }
+ return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
+ self::fe_cmov($t->yplusx, $u->yplusx, $b),
+ self::fe_cmov($t->yminusx, $u->yminusx, $b),
+ self::fe_cmov($t->xy2d, $u->xy2d, $b)
+ );
+ }
+
+ /**
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u
+ * @param int $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
+ */
+ public static function ge_cmov_cached(
+ ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t,
+ ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u,
+ $b
+ ) {
+ $b &= 1;
+ $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
+ $ret->YplusX = self::fe_cmov($t->YplusX, $u->YplusX, $b);
+ $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b);
+ $ret->Z = self::fe_cmov($t->Z, $u->Z, $b);
+ $ret->T2d = self::fe_cmov($t->T2d, $u->T2d, $b);
+ return $ret;
+ }
+
+ /**
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached
+ * @param int $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
+ * @throws SodiumException
+ */
+ public static function ge_cmov8_cached(array $cached, $b)
+ {
+ // const unsigned char bnegative = negative(b);
+ // const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1));
+ $bnegative = self::negative($b);
+ $babs = $b - (((-$bnegative) & $b) << 1);
+
+ // ge25519_cached_0(t);
+ $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
+ self::fe_1(),
+ self::fe_1(),
+ self::fe_1(),
+ self::fe_0()
+ );
+
+ // ge25519_cmov_cached(t, &cached[0], equal(babs, 1));
+ // ge25519_cmov_cached(t, &cached[1], equal(babs, 2));
+ // ge25519_cmov_cached(t, &cached[2], equal(babs, 3));
+ // ge25519_cmov_cached(t, &cached[3], equal(babs, 4));
+ // ge25519_cmov_cached(t, &cached[4], equal(babs, 5));
+ // ge25519_cmov_cached(t, &cached[5], equal(babs, 6));
+ // ge25519_cmov_cached(t, &cached[6], equal(babs, 7));
+ // ge25519_cmov_cached(t, &cached[7], equal(babs, 8));
+ for ($x = 0; $x < 8; ++$x) {
+ $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1));
+ }
+
+ // fe25519_copy(minust.YplusX, t->YminusX);
+ // fe25519_copy(minust.YminusX, t->YplusX);
+ // fe25519_copy(minust.Z, t->Z);
+ // fe25519_neg(minust.T2d, t->T2d);
+ $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
+ self::fe_copy($t->YminusX),
+ self::fe_copy($t->YplusX),
+ self::fe_copy($t->Z),
+ self::fe_neg($t->T2d)
+ );
+ return self::ge_cmov_cached($t, $minust, $bnegative);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param int $pos
+ * @param int $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
+ * @throws SodiumException
+ * @throws TypeError
+ * @psalm-suppress MixedArgument
+ * @psalm-suppress MixedArrayAccess
+ * @psalm-suppress MixedArrayOffset
+ */
+ public static function ge_select($pos = 0, $b = 0)
+ {
+ static $base = null;
+ if ($base === null) {
+ $base = array();
+ /** @var int $i */
+ foreach (self::$base as $i => $bas) {
+ for ($j = 0; $j < 8; ++$j) {
+ $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
+ );
+ }
+ }
+ }
+ /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
+ if (!is_int($pos)) {
+ throw new InvalidArgumentException('Position must be an integer');
+ }
+ if ($pos < 0 || $pos > 31) {
+ throw new RangeException('Position is out of range [0, 31]');
+ }
+
+ $bnegative = self::negative($b);
+ $babs = $b - (((-$bnegative) & $b) << 1);
+
+ $t = self::ge_precomp_0();
+ for ($i = 0; $i < 8; ++$i) {
+ $t = self::cmov(
+ $t,
+ $base[$pos][$i],
+ self::equal($babs, $i + 1)
+ );
+ }
+ $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
+ self::fe_copy($t->yminusx),
+ self::fe_copy($t->yplusx),
+ self::fe_neg($t->xy2d)
+ );
+ return self::cmov($t, $minusT, $bnegative);
+ }
+
+ /**
+ * Subtract two group elements.
+ *
+ * r = p - q
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
+ */
+ public static function ge_sub(
+ ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
+ ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
+ ) {
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
+
+ $r->X = self::fe_add($p->Y, $p->X);
+ $r->Y = self::fe_sub($p->Y, $p->X);
+ $r->Z = self::fe_mul($r->X, $q->YminusX);
+ $r->Y = self::fe_mul($r->Y, $q->YplusX);
+ $r->T = self::fe_mul($q->T2d, $p->T);
+ $r->X = self::fe_mul($p->Z, $q->Z);
+ $t0 = self::fe_add($r->X, $r->X);
+ $r->X = self::fe_sub($r->Z, $r->Y);
+ $r->Y = self::fe_add($r->Z, $r->Y);
+ $r->Z = self::fe_sub($t0, $r->T);
+ $r->T = self::fe_add($t0, $r->T);
+
+ return $r;
+ }
+
+ /**
+ * Convert a group element to a byte string.
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
+ {
+ $recip = self::fe_invert($h->Z);
+ $x = self::fe_mul($h->X, $recip);
+ $y = self::fe_mul($h->Y, $recip);
+ $s = self::fe_tobytes($y);
+ $s[31] = self::intToChr(
+ self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
+ );
+ return $s;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $a
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
+ * @param string $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
+ * @throws SodiumException
+ * @throws TypeError
+ * @psalm-suppress MixedArgument
+ * @psalm-suppress MixedArrayAccess
+ */
+ public static function ge_double_scalarmult_vartime(
+ $a,
+ ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
+ $b
+ ) {
+ /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
+ $Ai = array();
+
+ /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
+ static $Bi = array();
+ if (!$Bi) {
+ for ($i = 0; $i < 8; ++$i) {
+ $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
+ ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
+ );
+ }
+ }
+ for ($i = 0; $i < 8; ++$i) {
+ $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
+ self::fe_0(),
+ self::fe_0(),
+ self::fe_0(),
+ self::fe_0()
+ );
+ }
+
+ # slide(aslide,a);
+ # slide(bslide,b);
+ /** @var array<int, int> $aslide */
+ $aslide = self::slide($a);
+ /** @var array<int, int> $bslide */
+ $bslide = self::slide($b);
+
+ # ge_p3_to_cached(&Ai[0],A);
+ # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+ $Ai[0] = self::ge_p3_to_cached($A);
+ $t = self::ge_p3_dbl($A);
+ $A2 = self::ge_p1p1_to_p3($t);
+
+ # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+ # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+ # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+ # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+ # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+ # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+ # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+ for ($i = 0; $i < 7; ++$i) {
+ $t = self::ge_add($A2, $Ai[$i]);
+ $u = self::ge_p1p1_to_p3($t);
+ $Ai[$i + 1] = self::ge_p3_to_cached($u);
+ }
+
+ # ge_p2_0(r);
+ $r = self::ge_p2_0();
+
+ # for (i = 255;i >= 0;--i) {
+ # if (aslide[i] || bslide[i]) break;
+ # }
+ $i = 255;
+ for (; $i >= 0; --$i) {
+ if ($aslide[$i] || $bslide[$i]) {
+ break;
+ }
+ }
+
+ # for (;i >= 0;--i) {
+ for (; $i >= 0; --$i) {
+ # ge_p2_dbl(&t,r);
+ $t = self::ge_p2_dbl($r);
+
+ # if (aslide[i] > 0) {
+ if ($aslide[$i] > 0) {
+ # ge_p1p1_to_p3(&u,&t);
+ # ge_add(&t,&u,&Ai[aslide[i]/2]);
+ $u = self::ge_p1p1_to_p3($t);
+ $t = self::ge_add(
+ $u,
+ $Ai[(int) floor($aslide[$i] / 2)]
+ );
+ # } else if (aslide[i] < 0) {
+ } elseif ($aslide[$i] < 0) {
+ # ge_p1p1_to_p3(&u,&t);
+ # ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+ $u = self::ge_p1p1_to_p3($t);
+ $t = self::ge_sub(
+ $u,
+ $Ai[(int) floor(-$aslide[$i] / 2)]
+ );
+ }
+
+ # if (bslide[i] > 0) {
+ if ($bslide[$i] > 0) {
+ /** @var int $index */
+ $index = (int) floor($bslide[$i] / 2);
+ # ge_p1p1_to_p3(&u,&t);
+ # ge_madd(&t,&u,&Bi[bslide[i]/2]);
+ $u = self::ge_p1p1_to_p3($t);
+ $t = self::ge_madd($t, $u, $Bi[$index]);
+ # } else if (bslide[i] < 0) {
+ } elseif ($bslide[$i] < 0) {
+ /** @var int $index */
+ $index = (int) floor(-$bslide[$i] / 2);
+ # ge_p1p1_to_p3(&u,&t);
+ # ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+ $u = self::ge_p1p1_to_p3($t);
+ $t = self::ge_msub($t, $u, $Bi[$index]);
+ }
+ # ge_p1p1_to_p2(r,&t);
+ $r = self::ge_p1p1_to_p2($t);
+ }
+ return $r;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $a
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
+ * @throws SodiumException
+ * @throws TypeError
+ * @psalm-suppress MixedAssignment
+ * @psalm-suppress MixedOperand
+ */
+ public static function ge_scalarmult($a, $p)
+ {
+ $e = array_fill(0, 64, 0);
+
+ /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */
+ $pi = array();
+
+ // ge25519_p3_to_cached(&pi[1 - 1], p); /* p */
+ $pi[0] = self::ge_p3_to_cached($p);
+
+ // ge25519_p3_dbl(&t2, p);
+ // ge25519_p1p1_to_p3(&p2, &t2);
+ // ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */
+ $t2 = self::ge_p3_dbl($p);
+ $p2 = self::ge_p1p1_to_p3($t2);
+ $pi[1] = self::ge_p3_to_cached($p2);
+
+ // ge25519_add_cached(&t3, p, &pi[2 - 1]);
+ // ge25519_p1p1_to_p3(&p3, &t3);
+ // ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */
+ $t3 = self::ge_add($p, $pi[1]);
+ $p3 = self::ge_p1p1_to_p3($t3);
+ $pi[2] = self::ge_p3_to_cached($p3);
+
+ // ge25519_p3_dbl(&t4, &p2);
+ // ge25519_p1p1_to_p3(&p4, &t4);
+ // ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */
+ $t4 = self::ge_p3_dbl($p2);
+ $p4 = self::ge_p1p1_to_p3($t4);
+ $pi[3] = self::ge_p3_to_cached($p4);
+
+ // ge25519_add_cached(&t5, p, &pi[4 - 1]);
+ // ge25519_p1p1_to_p3(&p5, &t5);
+ // ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */
+ $t5 = self::ge_add($p, $pi[3]);
+ $p5 = self::ge_p1p1_to_p3($t5);
+ $pi[4] = self::ge_p3_to_cached($p5);
+
+ // ge25519_p3_dbl(&t6, &p3);
+ // ge25519_p1p1_to_p3(&p6, &t6);
+ // ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */
+ $t6 = self::ge_p3_dbl($p3);
+ $p6 = self::ge_p1p1_to_p3($t6);
+ $pi[5] = self::ge_p3_to_cached($p6);
+
+ // ge25519_add_cached(&t7, p, &pi[6 - 1]);
+ // ge25519_p1p1_to_p3(&p7, &t7);
+ // ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */
+ $t7 = self::ge_add($p, $pi[5]);
+ $p7 = self::ge_p1p1_to_p3($t7);
+ $pi[6] = self::ge_p3_to_cached($p7);
+
+ // ge25519_p3_dbl(&t8, &p4);
+ // ge25519_p1p1_to_p3(&p8, &t8);
+ // ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */
+ $t8 = self::ge_p3_dbl($p4);
+ $p8 = self::ge_p1p1_to_p3($t8);
+ $pi[7] = self::ge_p3_to_cached($p8);
+
+
+ // for (i = 0; i < 32; ++i) {
+ // e[2 * i + 0] = (a[i] >> 0) & 15;
+ // e[2 * i + 1] = (a[i] >> 4) & 15;
+ // }
+ for ($i = 0; $i < 32; ++$i) {
+ $e[($i << 1) ] = self::chrToInt($a[$i]) & 15;
+ $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15;
+ }
+ // /* each e[i] is between 0 and 15 */
+ // /* e[63] is between 0 and 7 */
+
+ // carry = 0;
+ // for (i = 0; i < 63; ++i) {
+ // e[i] += carry;
+ // carry = e[i] + 8;
+ // carry >>= 4;
+ // e[i] -= carry * ((signed char) 1 << 4);
+ // }
+ $carry = 0;
+ for ($i = 0; $i < 63; ++$i) {
+ $e[$i] += $carry;
+ $carry = $e[$i] + 8;
+ $carry >>= 4;
+ $e[$i] -= $carry << 4;
+ }
+ // e[63] += carry;
+ // /* each e[i] is between -8 and 8 */
+ $e[63] += $carry;
+
+ // ge25519_p3_0(h);
+ $h = self::ge_p3_0();
+
+ // for (i = 63; i != 0; i--) {
+ for ($i = 63; $i != 0; --$i) {
+ // ge25519_cmov8_cached(&t, pi, e[i]);
+ $t = self::ge_cmov8_cached($pi, $e[$i]);
+ // ge25519_add_cached(&r, h, &t);
+ $r = self::ge_add($h, $t);
+
+ // ge25519_p1p1_to_p2(&s, &r);
+ // ge25519_p2_dbl(&r, &s);
+ // ge25519_p1p1_to_p2(&s, &r);
+ // ge25519_p2_dbl(&r, &s);
+ // ge25519_p1p1_to_p2(&s, &r);
+ // ge25519_p2_dbl(&r, &s);
+ // ge25519_p1p1_to_p2(&s, &r);
+ // ge25519_p2_dbl(&r, &s);
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+
+ // ge25519_p1p1_to_p3(h, &r); /* *16 */
+ $h = self::ge_p1p1_to_p3($r); /* *16 */
+ }
+
+ // ge25519_cmov8_cached(&t, pi, e[i]);
+ // ge25519_add_cached(&r, h, &t);
+ // ge25519_p1p1_to_p3(h, &r);
+ $t = self::ge_cmov8_cached($pi, $e[0]);
+ $r = self::ge_add($h, $t);
+ return self::ge_p1p1_to_p3($r);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $a
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
+ * @throws SodiumException
+ * @throws TypeError
+ * @psalm-suppress MixedAssignment
+ * @psalm-suppress MixedOperand
+ */
+ public static function ge_scalarmult_base($a)
+ {
+ /** @var array<int, int> $e */
+ $e = array();
+ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
+
+ for ($i = 0; $i < 32; ++$i) {
+ $dbl = (int) $i << 1;
+ $e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
+ $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
+ }
+
+ $carry = 0;
+ for ($i = 0; $i < 63; ++$i) {
+ $e[$i] += $carry;
+ $carry = $e[$i] + 8;
+ $carry >>= 4;
+ $e[$i] -= $carry << 4;
+ }
+ $e[63] += (int) $carry;
+
+ $h = self::ge_p3_0();
+
+ for ($i = 1; $i < 64; $i += 2) {
+ $t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
+ $r = self::ge_madd($r, $h, $t);
+ $h = self::ge_p1p1_to_p3($r);
+ }
+
+ $r = self::ge_p3_dbl($h);
+
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+ $s = self::ge_p1p1_to_p2($r);
+ $r = self::ge_p2_dbl($s);
+
+ $h = self::ge_p1p1_to_p3($r);
+
+ for ($i = 0; $i < 64; $i += 2) {
+ $t = self::ge_select($i >> 1, (int) $e[$i]);
+ $r = self::ge_madd($r, $h, $t);
+ $h = self::ge_p1p1_to_p3($r);
+ }
+ return $h;
+ }
+
+ /**
+ * Calculates (ab + c) mod l
+ * where l = 2^252 + 27742317777372353535851937790883648493
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param string $a
+ * @param string $b
+ * @param string $c
+ * @return string
+ * @throws TypeError
+ */
+ public static function sc_muladd($a, $b, $c)
+ {
+ $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
+ $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
+ $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
+ $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
+ $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
+ $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
+ $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
+ $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
+ $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
+ $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
+ $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
+ $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
+
+ $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
+ $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
+ $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
+ $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
+ $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
+ $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
+ $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
+ $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
+ $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
+ $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
+ $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
+ $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
+
+ $c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
+ $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5);
+ $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2);
+ $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7);
+ $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4);
+ $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1);
+ $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6);
+ $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3);
+ $c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
+ $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5);
+ $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2);
+ $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);
+
+ /* Can't really avoid the pyramid here: */
+ $s0 = $c0 + self::mul($a0, $b0, 24);
+ $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
+ $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24);
+ $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
+ $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
+ self::mul($a4, $b0, 24);
+ $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
+ self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
+ $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
+ self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24);
+ $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
+ self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
+ $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
+ self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
+ self::mul($a8, $b0, 24);
+ $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
+ self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
+ self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
+ $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
+ self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
+ self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24);
+ $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
+ self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
+ self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
+ $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
+ self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
+ self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24);
+ $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
+ self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
+ self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
+ $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
+ self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
+ self::mul($a11, $b3, 24);
+ $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
+ self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
+ $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
+ self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24);
+ $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
+ self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
+ $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
+ self::mul($a11, $b7, 24);
+ $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
+ $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24);
+ $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
+ $s22 = self::mul($a11, $b11, 24);
+ $s23 = 0;
+
+ $carry0 = ($s0 + (1 << 20)) >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry2 = ($s2 + (1 << 20)) >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry4 = ($s4 + (1 << 20)) >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ $carry12 = ($s12 + (1 << 20)) >> 21;
+ $s13 += $carry12;
+ $s12 -= $carry12 << 21;
+ $carry14 = ($s14 + (1 << 20)) >> 21;
+ $s15 += $carry14;
+ $s14 -= $carry14 << 21;
+ $carry16 = ($s16 + (1 << 20)) >> 21;
+ $s17 += $carry16;
+ $s16 -= $carry16 << 21;
+ $carry18 = ($s18 + (1 << 20)) >> 21;
+ $s19 += $carry18;
+ $s18 -= $carry18 << 21;
+ $carry20 = ($s20 + (1 << 20)) >> 21;
+ $s21 += $carry20;
+ $s20 -= $carry20 << 21;
+ $carry22 = ($s22 + (1 << 20)) >> 21;
+ $s23 += $carry22;
+ $s22 -= $carry22 << 21;
+
+ $carry1 = ($s1 + (1 << 20)) >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry3 = ($s3 + (1 << 20)) >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry5 = ($s5 + (1 << 20)) >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+ $carry13 = ($s13 + (1 << 20)) >> 21;
+ $s14 += $carry13;
+ $s13 -= $carry13 << 21;
+ $carry15 = ($s15 + (1 << 20)) >> 21;
+ $s16 += $carry15;
+ $s15 -= $carry15 << 21;
+ $carry17 = ($s17 + (1 << 20)) >> 21;
+ $s18 += $carry17;
+ $s17 -= $carry17 << 21;
+ $carry19 = ($s19 + (1 << 20)) >> 21;
+ $s20 += $carry19;
+ $s19 -= $carry19 << 21;
+ $carry21 = ($s21 + (1 << 20)) >> 21;
+ $s22 += $carry21;
+ $s21 -= $carry21 << 21;
+
+ $s11 += self::mul($s23, 666643, 20);
+ $s12 += self::mul($s23, 470296, 19);
+ $s13 += self::mul($s23, 654183, 20);
+ $s14 -= self::mul($s23, 997805, 20);
+ $s15 += self::mul($s23, 136657, 18);
+ $s16 -= self::mul($s23, 683901, 20);
+
+ $s10 += self::mul($s22, 666643, 20);
+ $s11 += self::mul($s22, 470296, 19);
+ $s12 += self::mul($s22, 654183, 20);
+ $s13 -= self::mul($s22, 997805, 20);
+ $s14 += self::mul($s22, 136657, 18);
+ $s15 -= self::mul($s22, 683901, 20);
+
+ $s9 += self::mul($s21, 666643, 20);
+ $s10 += self::mul($s21, 470296, 19);
+ $s11 += self::mul($s21, 654183, 20);
+ $s12 -= self::mul($s21, 997805, 20);
+ $s13 += self::mul($s21, 136657, 18);
+ $s14 -= self::mul($s21, 683901, 20);
+
+ $s8 += self::mul($s20, 666643, 20);
+ $s9 += self::mul($s20, 470296, 19);
+ $s10 += self::mul($s20, 654183, 20);
+ $s11 -= self::mul($s20, 997805, 20);
+ $s12 += self::mul($s20, 136657, 18);
+ $s13 -= self::mul($s20, 683901, 20);
+
+ $s7 += self::mul($s19, 666643, 20);
+ $s8 += self::mul($s19, 470296, 19);
+ $s9 += self::mul($s19, 654183, 20);
+ $s10 -= self::mul($s19, 997805, 20);
+ $s11 += self::mul($s19, 136657, 18);
+ $s12 -= self::mul($s19, 683901, 20);
+
+ $s6 += self::mul($s18, 666643, 20);
+ $s7 += self::mul($s18, 470296, 19);
+ $s8 += self::mul($s18, 654183, 20);
+ $s9 -= self::mul($s18, 997805, 20);
+ $s10 += self::mul($s18, 136657, 18);
+ $s11 -= self::mul($s18, 683901, 20);
+
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ $carry12 = ($s12 + (1 << 20)) >> 21;
+ $s13 += $carry12;
+ $s12 -= $carry12 << 21;
+ $carry14 = ($s14 + (1 << 20)) >> 21;
+ $s15 += $carry14;
+ $s14 -= $carry14 << 21;
+ $carry16 = ($s16 + (1 << 20)) >> 21;
+ $s17 += $carry16;
+ $s16 -= $carry16 << 21;
+
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+ $carry13 = ($s13 + (1 << 20)) >> 21;
+ $s14 += $carry13;
+ $s13 -= $carry13 << 21;
+ $carry15 = ($s15 + (1 << 20)) >> 21;
+ $s16 += $carry15;
+ $s15 -= $carry15 << 21;
+
+ $s5 += self::mul($s17, 666643, 20);
+ $s6 += self::mul($s17, 470296, 19);
+ $s7 += self::mul($s17, 654183, 20);
+ $s8 -= self::mul($s17, 997805, 20);
+ $s9 += self::mul($s17, 136657, 18);
+ $s10 -= self::mul($s17, 683901, 20);
+
+ $s4 += self::mul($s16, 666643, 20);
+ $s5 += self::mul($s16, 470296, 19);
+ $s6 += self::mul($s16, 654183, 20);
+ $s7 -= self::mul($s16, 997805, 20);
+ $s8 += self::mul($s16, 136657, 18);
+ $s9 -= self::mul($s16, 683901, 20);
+
+ $s3 += self::mul($s15, 666643, 20);
+ $s4 += self::mul($s15, 470296, 19);
+ $s5 += self::mul($s15, 654183, 20);
+ $s6 -= self::mul($s15, 997805, 20);
+ $s7 += self::mul($s15, 136657, 18);
+ $s8 -= self::mul($s15, 683901, 20);
+
+ $s2 += self::mul($s14, 666643, 20);
+ $s3 += self::mul($s14, 470296, 19);
+ $s4 += self::mul($s14, 654183, 20);
+ $s5 -= self::mul($s14, 997805, 20);
+ $s6 += self::mul($s14, 136657, 18);
+ $s7 -= self::mul($s14, 683901, 20);
+
+ $s1 += self::mul($s13, 666643, 20);
+ $s2 += self::mul($s13, 470296, 19);
+ $s3 += self::mul($s13, 654183, 20);
+ $s4 -= self::mul($s13, 997805, 20);
+ $s5 += self::mul($s13, 136657, 18);
+ $s6 -= self::mul($s13, 683901, 20);
+
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+ $s12 = 0;
+
+ $carry0 = ($s0 + (1 << 20)) >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry2 = ($s2 + (1 << 20)) >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry4 = ($s4 + (1 << 20)) >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+
+ $carry1 = ($s1 + (1 << 20)) >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry3 = ($s3 + (1 << 20)) >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry5 = ($s5 + (1 << 20)) >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+ $s12 = 0;
+
+ $carry0 = $s0 >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry1 = $s1 >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry2 = $s2 >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry3 = $s3 >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry4 = $s4 >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry5 = $s5 >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry6 = $s6 >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry7 = $s7 >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry8 = $s8 >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry9 = $s9 >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry10 = $s10 >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ $carry11 = $s11 >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+
+ $carry0 = $s0 >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry1 = $s1 >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry2 = $s2 >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry3 = $s3 >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry4 = $s4 >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry5 = $s5 >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry6 = $s6 >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry7 = $s7 >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry8 = $s8 >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry9 = $s9 >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry10 = $s10 >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+
+ /**
+ * @var array<int, int>
+ */
+ $arr = array(
+ (int) (0xff & ($s0 >> 0)),
+ (int) (0xff & ($s0 >> 8)),
+ (int) (0xff & (($s0 >> 16) | $s1 << 5)),
+ (int) (0xff & ($s1 >> 3)),
+ (int) (0xff & ($s1 >> 11)),
+ (int) (0xff & (($s1 >> 19) | $s2 << 2)),
+ (int) (0xff & ($s2 >> 6)),
+ (int) (0xff & (($s2 >> 14) | $s3 << 7)),
+ (int) (0xff & ($s3 >> 1)),
+ (int) (0xff & ($s3 >> 9)),
+ (int) (0xff & (($s3 >> 17) | $s4 << 4)),
+ (int) (0xff & ($s4 >> 4)),
+ (int) (0xff & ($s4 >> 12)),
+ (int) (0xff & (($s4 >> 20) | $s5 << 1)),
+ (int) (0xff & ($s5 >> 7)),
+ (int) (0xff & (($s5 >> 15) | $s6 << 6)),
+ (int) (0xff & ($s6 >> 2)),
+ (int) (0xff & ($s6 >> 10)),
+ (int) (0xff & (($s6 >> 18) | $s7 << 3)),
+ (int) (0xff & ($s7 >> 5)),
+ (int) (0xff & ($s7 >> 13)),
+ (int) (0xff & ($s8 >> 0)),
+ (int) (0xff & ($s8 >> 8)),
+ (int) (0xff & (($s8 >> 16) | $s9 << 5)),
+ (int) (0xff & ($s9 >> 3)),
+ (int) (0xff & ($s9 >> 11)),
+ (int) (0xff & (($s9 >> 19) | $s10 << 2)),
+ (int) (0xff & ($s10 >> 6)),
+ (int) (0xff & (($s10 >> 14) | $s11 << 7)),
+ (int) (0xff & ($s11 >> 1)),
+ (int) (0xff & ($s11 >> 9)),
+ 0xff & ($s11 >> 17)
+ );
+ return self::intArrayToString($arr);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $s
+ * @return string
+ * @throws TypeError
+ */
+ public static function sc_reduce($s)
+ {
+ $s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
+ $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5);
+ $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2);
+ $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7);
+ $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4);
+ $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1);
+ $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6);
+ $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3);
+ $s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
+ $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5);
+ $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2);
+ $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7);
+ $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4);
+ $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1);
+ $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6);
+ $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3);
+ $s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
+ $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5);
+ $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2);
+ $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7);
+ $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4);
+ $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1);
+ $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6);
+ $s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3);
+
+ $s11 += self::mul($s23, 666643, 20);
+ $s12 += self::mul($s23, 470296, 19);
+ $s13 += self::mul($s23, 654183, 20);
+ $s14 -= self::mul($s23, 997805, 20);
+ $s15 += self::mul($s23, 136657, 18);
+ $s16 -= self::mul($s23, 683901, 20);
+
+ $s10 += self::mul($s22, 666643, 20);
+ $s11 += self::mul($s22, 470296, 19);
+ $s12 += self::mul($s22, 654183, 20);
+ $s13 -= self::mul($s22, 997805, 20);
+ $s14 += self::mul($s22, 136657, 18);
+ $s15 -= self::mul($s22, 683901, 20);
+
+ $s9 += self::mul($s21, 666643, 20);
+ $s10 += self::mul($s21, 470296, 19);
+ $s11 += self::mul($s21, 654183, 20);
+ $s12 -= self::mul($s21, 997805, 20);
+ $s13 += self::mul($s21, 136657, 18);
+ $s14 -= self::mul($s21, 683901, 20);
+
+ $s8 += self::mul($s20, 666643, 20);
+ $s9 += self::mul($s20, 470296, 19);
+ $s10 += self::mul($s20, 654183, 20);
+ $s11 -= self::mul($s20, 997805, 20);
+ $s12 += self::mul($s20, 136657, 18);
+ $s13 -= self::mul($s20, 683901, 20);
+
+ $s7 += self::mul($s19, 666643, 20);
+ $s8 += self::mul($s19, 470296, 19);
+ $s9 += self::mul($s19, 654183, 20);
+ $s10 -= self::mul($s19, 997805, 20);
+ $s11 += self::mul($s19, 136657, 18);
+ $s12 -= self::mul($s19, 683901, 20);
+
+ $s6 += self::mul($s18, 666643, 20);
+ $s7 += self::mul($s18, 470296, 19);
+ $s8 += self::mul($s18, 654183, 20);
+ $s9 -= self::mul($s18, 997805, 20);
+ $s10 += self::mul($s18, 136657, 18);
+ $s11 -= self::mul($s18, 683901, 20);
+
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ $carry12 = ($s12 + (1 << 20)) >> 21;
+ $s13 += $carry12;
+ $s12 -= $carry12 << 21;
+ $carry14 = ($s14 + (1 << 20)) >> 21;
+ $s15 += $carry14;
+ $s14 -= $carry14 << 21;
+ $carry16 = ($s16 + (1 << 20)) >> 21;
+ $s17 += $carry16;
+ $s16 -= $carry16 << 21;
+
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+ $carry13 = ($s13 + (1 << 20)) >> 21;
+ $s14 += $carry13;
+ $s13 -= $carry13 << 21;
+ $carry15 = ($s15 + (1 << 20)) >> 21;
+ $s16 += $carry15;
+ $s15 -= $carry15 << 21;
+
+ $s5 += self::mul($s17, 666643, 20);
+ $s6 += self::mul($s17, 470296, 19);
+ $s7 += self::mul($s17, 654183, 20);
+ $s8 -= self::mul($s17, 997805, 20);
+ $s9 += self::mul($s17, 136657, 18);
+ $s10 -= self::mul($s17, 683901, 20);
+
+ $s4 += self::mul($s16, 666643, 20);
+ $s5 += self::mul($s16, 470296, 19);
+ $s6 += self::mul($s16, 654183, 20);
+ $s7 -= self::mul($s16, 997805, 20);
+ $s8 += self::mul($s16, 136657, 18);
+ $s9 -= self::mul($s16, 683901, 20);
+
+ $s3 += self::mul($s15, 666643, 20);
+ $s4 += self::mul($s15, 470296, 19);
+ $s5 += self::mul($s15, 654183, 20);
+ $s6 -= self::mul($s15, 997805, 20);
+ $s7 += self::mul($s15, 136657, 18);
+ $s8 -= self::mul($s15, 683901, 20);
+
+ $s2 += self::mul($s14, 666643, 20);
+ $s3 += self::mul($s14, 470296, 19);
+ $s4 += self::mul($s14, 654183, 20);
+ $s5 -= self::mul($s14, 997805, 20);
+ $s6 += self::mul($s14, 136657, 18);
+ $s7 -= self::mul($s14, 683901, 20);
+
+ $s1 += self::mul($s13, 666643, 20);
+ $s2 += self::mul($s13, 470296, 19);
+ $s3 += self::mul($s13, 654183, 20);
+ $s4 -= self::mul($s13, 997805, 20);
+ $s5 += self::mul($s13, 136657, 18);
+ $s6 -= self::mul($s13, 683901, 20);
+
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+ $s12 = 0;
+
+ $carry0 = ($s0 + (1 << 20)) >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry2 = ($s2 + (1 << 20)) >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry4 = ($s4 + (1 << 20)) >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+
+ $carry1 = ($s1 + (1 << 20)) >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry3 = ($s3 + (1 << 20)) >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry5 = ($s5 + (1 << 20)) >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+ $s12 = 0;
+
+ $carry0 = $s0 >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry1 = $s1 >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry2 = $s2 >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry3 = $s3 >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry4 = $s4 >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry5 = $s5 >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry6 = $s6 >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry7 = $s7 >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry8 = $s8 >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry9 = $s9 >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry10 = $s10 >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ $carry11 = $s11 >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+
+ $carry0 = $s0 >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ $carry1 = $s1 >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ $carry2 = $s2 >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ $carry3 = $s3 >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ $carry4 = $s4 >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ $carry5 = $s5 >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ $carry6 = $s6 >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ $carry7 = $s7 >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ $carry8 = $s8 >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ $carry9 = $s9 >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ $carry10 = $s10 >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+
+ /**
+ * @var array<int, int>
+ */
+ $arr = array(
+ (int) ($s0 >> 0),
+ (int) ($s0 >> 8),
+ (int) (($s0 >> 16) | $s1 << 5),
+ (int) ($s1 >> 3),
+ (int) ($s1 >> 11),
+ (int) (($s1 >> 19) | $s2 << 2),
+ (int) ($s2 >> 6),
+ (int) (($s2 >> 14) | $s3 << 7),
+ (int) ($s3 >> 1),
+ (int) ($s3 >> 9),
+ (int) (($s3 >> 17) | $s4 << 4),
+ (int) ($s4 >> 4),
+ (int) ($s4 >> 12),
+ (int) (($s4 >> 20) | $s5 << 1),
+ (int) ($s5 >> 7),
+ (int) (($s5 >> 15) | $s6 << 6),
+ (int) ($s6 >> 2),
+ (int) ($s6 >> 10),
+ (int) (($s6 >> 18) | $s7 << 3),
+ (int) ($s7 >> 5),
+ (int) ($s7 >> 13),
+ (int) ($s8 >> 0),
+ (int) ($s8 >> 8),
+ (int) (($s8 >> 16) | $s9 << 5),
+ (int) ($s9 >> 3),
+ (int) ($s9 >> 11),
+ (int) (($s9 >> 19) | $s10 << 2),
+ (int) ($s10 >> 6),
+ (int) (($s10 >> 14) | $s11 << 7),
+ (int) ($s11 >> 1),
+ (int) ($s11 >> 9),
+ (int) $s11 >> 17
+ );
+ return self::intArrayToString($arr);
+ }
+
+ /**
+ * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
+ * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
+ */
+ public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A)
+ {
+ $aslide = array(
+ 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
+ 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
+ 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
+ 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
+ 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+ );
+
+ /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
+ $Ai = array();
+
+ # ge_p3_to_cached(&Ai[0], A);
+ $Ai[0] = self::ge_p3_to_cached($A);
+ # ge_p3_dbl(&t, A);
+ $t = self::ge_p3_dbl($A);
+ # ge_p1p1_to_p3(&A2, &t);
+ $A2 = self::ge_p1p1_to_p3($t);
+
+ for ($i = 1; $i < 8; ++$i) {
+ # ge_add(&t, &A2, &Ai[0]);
+ $t = self::ge_add($A2, $Ai[$i - 1]);
+ # ge_p1p1_to_p3(&u, &t);
+ $u = self::ge_p1p1_to_p3($t);
+ # ge_p3_to_cached(&Ai[i], &u);
+ $Ai[$i] = self::ge_p3_to_cached($u);
+ }
+
+ $r = self::ge_p3_0();
+ for ($i = 252; $i >= 0; --$i) {
+ $t = self::ge_p3_dbl($r);
+ if ($aslide[$i] > 0) {
+ # ge_p1p1_to_p3(&u, &t);
+ $u = self::ge_p1p1_to_p3($t);
+ # ge_add(&t, &u, &Ai[aslide[i] / 2]);
+ $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
+ } elseif ($aslide[$i] < 0) {
+ # ge_p1p1_to_p3(&u, &t);
+ $u = self::ge_p1p1_to_p3($t);
+ # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
+ $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
+ }
+ }
+
+ # ge_p1p1_to_p3(r, &t);
+ return self::ge_p1p1_to_p3($t);
+ }
+
+ /**
+ * @param string $a
+ * @param string $b
+ * @return string
+ */
+ public static function sc25519_mul($a, $b)
+ {
+ // int64_t a0 = 2097151 & load_3(a);
+ // int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+ // int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+ // int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+ // int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+ // int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+ // int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+ // int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+ // int64_t a8 = 2097151 & load_3(a + 21);
+ // int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+ // int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+ // int64_t a11 = (load_4(a + 28) >> 7);
+ $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
+ $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
+ $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
+ $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
+ $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
+ $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
+ $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
+ $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
+ $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
+ $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
+ $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
+ $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
+
+ // int64_t b0 = 2097151 & load_3(b);
+ // int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+ // int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+ // int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+ // int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+ // int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+ // int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+ // int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+ // int64_t b8 = 2097151 & load_3(b + 21);
+ // int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+ // int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+ // int64_t b11 = (load_4(b + 28) >> 7);
+ $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
+ $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
+ $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
+ $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
+ $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
+ $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
+ $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
+ $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
+ $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
+ $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
+ $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
+ $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
+
+ // s0 = a0 * b0;
+ // s1 = a0 * b1 + a1 * b0;
+ // s2 = a0 * b2 + a1 * b1 + a2 * b0;
+ // s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
+ // s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
+ // s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
+ // s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
+ // s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
+ // a6 * b1 + a7 * b0;
+ // s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
+ // a6 * b2 + a7 * b1 + a8 * b0;
+ // s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
+ // a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
+ // s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
+ // a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
+ // s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
+ // a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
+ // s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 +
+ // a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
+ // s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 +
+ // a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
+ // s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 +
+ // a9 * b5 + a10 * b4 + a11 * b3;
+ // s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 +
+ // a10 * b5 + a11 * b4;
+ // s16 =
+ // a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
+ // s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
+ // s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
+ // s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
+ // s20 = a9 * b11 + a10 * b10 + a11 * b9;
+ // s21 = a10 * b11 + a11 * b10;
+ // s22 = a11 * b11;
+ // s23 = 0;
+ $s0 = self::mul($a0, $b0, 22);
+ $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22);
+ $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22);
+ $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22);
+ $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) +
+ self::mul($a4, $b0, 22);
+ $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) +
+ self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22);
+ $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) +
+ self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22);
+ $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) +
+ self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22);
+ $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) +
+ self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) +
+ self::mul($a8, $b0, 22);
+ $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) +
+ self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) +
+ self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22);
+ $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) +
+ self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) +
+ self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22);
+ $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) +
+ self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) +
+ self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22);
+ $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) +
+ self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) +
+ self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22);
+ $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) +
+ self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) +
+ self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22);
+ $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) +
+ self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) +
+ self::mul($a11, $b3, 22);
+ $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) +
+ self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22);
+ $s16 =
+ self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) +
+ self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22);
+ $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) +
+ self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22);
+ $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22)
+ + self::mul($a11, $b7, 22);
+ $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) +
+ self::mul($a11, $b8, 22);
+ $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22);
+ $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22);
+ $s22 = self::mul($a11, $b11, 22);
+ $s23 = 0;
+
+ // carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
+ // s1 += carry0;
+ // s0 -= carry0 * ((uint64_t) 1L << 21);
+ $carry0 = ($s0 + (1 << 20)) >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ // carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
+ // s3 += carry2;
+ // s2 -= carry2 * ((uint64_t) 1L << 21);
+ $carry2 = ($s2 + (1 << 20)) >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ // carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
+ // s5 += carry4;
+ // s4 -= carry4 * ((uint64_t) 1L << 21);
+ $carry4 = ($s4 + (1 << 20)) >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ // carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
+ // s7 += carry6;
+ // s6 -= carry6 * ((uint64_t) 1L << 21);
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ // carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
+ // s9 += carry8;
+ // s8 -= carry8 * ((uint64_t) 1L << 21);
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ // carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
+ // s11 += carry10;
+ // s10 -= carry10 * ((uint64_t) 1L << 21);
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ // carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
+ // s13 += carry12;
+ // s12 -= carry12 * ((uint64_t) 1L << 21);
+ $carry12 = ($s12 + (1 << 20)) >> 21;
+ $s13 += $carry12;
+ $s12 -= $carry12 << 21;
+ // carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
+ // s15 += carry14;
+ // s14 -= carry14 * ((uint64_t) 1L << 21);
+ $carry14 = ($s14 + (1 << 20)) >> 21;
+ $s15 += $carry14;
+ $s14 -= $carry14 << 21;
+ // carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
+ // s17 += carry16;
+ // s16 -= carry16 * ((uint64_t) 1L << 21);
+ $carry16 = ($s16 + (1 << 20)) >> 21;
+ $s17 += $carry16;
+ $s16 -= $carry16 << 21;
+ // carry18 = (s18 + (int64_t) (1L << 20)) >> 21;
+ // s19 += carry18;
+ // s18 -= carry18 * ((uint64_t) 1L << 21);
+ $carry18 = ($s18 + (1 << 20)) >> 21;
+ $s19 += $carry18;
+ $s18 -= $carry18 << 21;
+ // carry20 = (s20 + (int64_t) (1L << 20)) >> 21;
+ // s21 += carry20;
+ // s20 -= carry20 * ((uint64_t) 1L << 21);
+ $carry20 = ($s20 + (1 << 20)) >> 21;
+ $s21 += $carry20;
+ $s20 -= $carry20 << 21;
+ // carry22 = (s22 + (int64_t) (1L << 20)) >> 21;
+ // s23 += carry22;
+ // s22 -= carry22 * ((uint64_t) 1L << 21);
+ $carry22 = ($s22 + (1 << 20)) >> 21;
+ $s23 += $carry22;
+ $s22 -= $carry22 << 21;
+
+ // carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
+ // s2 += carry1;
+ // s1 -= carry1 * ((uint64_t) 1L << 21);
+ $carry1 = ($s1 + (1 << 20)) >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ // carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
+ // s4 += carry3;
+ // s3 -= carry3 * ((uint64_t) 1L << 21);
+ $carry3 = ($s3 + (1 << 20)) >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ // carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
+ // s6 += carry5;
+ // s5 -= carry5 * ((uint64_t) 1L << 21);
+ $carry5 = ($s5 + (1 << 20)) >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ // carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
+ // s8 += carry7;
+ // s7 -= carry7 * ((uint64_t) 1L << 21);
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ // carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
+ // s10 += carry9;
+ // s9 -= carry9 * ((uint64_t) 1L << 21);
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ // carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
+ // s12 += carry11;
+ // s11 -= carry11 * ((uint64_t) 1L << 21);
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+ // carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
+ // s14 += carry13;
+ // s13 -= carry13 * ((uint64_t) 1L << 21);
+ $carry13 = ($s13 + (1 << 20)) >> 21;
+ $s14 += $carry13;
+ $s13 -= $carry13 << 21;
+ // carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
+ // s16 += carry15;
+ // s15 -= carry15 * ((uint64_t) 1L << 21);
+ $carry15 = ($s15 + (1 << 20)) >> 21;
+ $s16 += $carry15;
+ $s15 -= $carry15 << 21;
+ // carry17 = (s17 + (int64_t) (1L << 20)) >> 21;
+ // s18 += carry17;
+ // s17 -= carry17 * ((uint64_t) 1L << 21);
+ $carry17 = ($s17 + (1 << 20)) >> 21;
+ $s18 += $carry17;
+ $s17 -= $carry17 << 21;
+ // carry19 = (s19 + (int64_t) (1L << 20)) >> 21;
+ // s20 += carry19;
+ // s19 -= carry19 * ((uint64_t) 1L << 21);
+ $carry19 = ($s19 + (1 << 20)) >> 21;
+ $s20 += $carry19;
+ $s19 -= $carry19 << 21;
+ // carry21 = (s21 + (int64_t) (1L << 20)) >> 21;
+ // s22 += carry21;
+ // s21 -= carry21 * ((uint64_t) 1L << 21);
+ $carry21 = ($s21 + (1 << 20)) >> 21;
+ $s22 += $carry21;
+ $s21 -= $carry21 << 21;
+
+ // s11 += s23 * 666643;
+ // s12 += s23 * 470296;
+ // s13 += s23 * 654183;
+ // s14 -= s23 * 997805;
+ // s15 += s23 * 136657;
+ // s16 -= s23 * 683901;
+ $s11 += self::mul($s23, 666643, 20);
+ $s12 += self::mul($s23, 470296, 19);
+ $s13 += self::mul($s23, 654183, 20);
+ $s14 -= self::mul($s23, 997805, 20);
+ $s15 += self::mul($s23, 136657, 18);
+ $s16 -= self::mul($s23, 683901, 20);
+
+ // s10 += s22 * 666643;
+ // s11 += s22 * 470296;
+ // s12 += s22 * 654183;
+ // s13 -= s22 * 997805;
+ // s14 += s22 * 136657;
+ // s15 -= s22 * 683901;
+ $s10 += self::mul($s22, 666643, 20);
+ $s11 += self::mul($s22, 470296, 19);
+ $s12 += self::mul($s22, 654183, 20);
+ $s13 -= self::mul($s22, 997805, 20);
+ $s14 += self::mul($s22, 136657, 18);
+ $s15 -= self::mul($s22, 683901, 20);
+
+ // s9 += s21 * 666643;
+ // s10 += s21 * 470296;
+ // s11 += s21 * 654183;
+ // s12 -= s21 * 997805;
+ // s13 += s21 * 136657;
+ // s14 -= s21 * 683901;
+ $s9 += self::mul($s21, 666643, 20);
+ $s10 += self::mul($s21, 470296, 19);
+ $s11 += self::mul($s21, 654183, 20);
+ $s12 -= self::mul($s21, 997805, 20);
+ $s13 += self::mul($s21, 136657, 18);
+ $s14 -= self::mul($s21, 683901, 20);
+
+ // s8 += s20 * 666643;
+ // s9 += s20 * 470296;
+ // s10 += s20 * 654183;
+ // s11 -= s20 * 997805;
+ // s12 += s20 * 136657;
+ // s13 -= s20 * 683901;
+ $s8 += self::mul($s20, 666643, 20);
+ $s9 += self::mul($s20, 470296, 19);
+ $s10 += self::mul($s20, 654183, 20);
+ $s11 -= self::mul($s20, 997805, 20);
+ $s12 += self::mul($s20, 136657, 18);
+ $s13 -= self::mul($s20, 683901, 20);
+
+ // s7 += s19 * 666643;
+ // s8 += s19 * 470296;
+ // s9 += s19 * 654183;
+ // s10 -= s19 * 997805;
+ // s11 += s19 * 136657;
+ // s12 -= s19 * 683901;
+ $s7 += self::mul($s19, 666643, 20);
+ $s8 += self::mul($s19, 470296, 19);
+ $s9 += self::mul($s19, 654183, 20);
+ $s10 -= self::mul($s19, 997805, 20);
+ $s11 += self::mul($s19, 136657, 18);
+ $s12 -= self::mul($s19, 683901, 20);
+
+ // s6 += s18 * 666643;
+ // s7 += s18 * 470296;
+ // s8 += s18 * 654183;
+ // s9 -= s18 * 997805;
+ // s10 += s18 * 136657;
+ // s11 -= s18 * 683901;
+ $s6 += self::mul($s18, 666643, 20);
+ $s7 += self::mul($s18, 470296, 19);
+ $s8 += self::mul($s18, 654183, 20);
+ $s9 -= self::mul($s18, 997805, 20);
+ $s10 += self::mul($s18, 136657, 18);
+ $s11 -= self::mul($s18, 683901, 20);
+
+ // carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
+ // s7 += carry6;
+ // s6 -= carry6 * ((uint64_t) 1L << 21);
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ // carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
+ // s9 += carry8;
+ // s8 -= carry8 * ((uint64_t) 1L << 21);
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ // carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
+ // s11 += carry10;
+ // s10 -= carry10 * ((uint64_t) 1L << 21);
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ // carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
+ // s13 += carry12;
+ // s12 -= carry12 * ((uint64_t) 1L << 21);
+ $carry12 = ($s12 + (1 << 20)) >> 21;
+ $s13 += $carry12;
+ $s12 -= $carry12 << 21;
+ // carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
+ // s15 += carry14;
+ // s14 -= carry14 * ((uint64_t) 1L << 21);
+ $carry14 = ($s14 + (1 << 20)) >> 21;
+ $s15 += $carry14;
+ $s14 -= $carry14 << 21;
+ // carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
+ // s17 += carry16;
+ // s16 -= carry16 * ((uint64_t) 1L << 21);
+ $carry16 = ($s16 + (1 << 20)) >> 21;
+ $s17 += $carry16;
+ $s16 -= $carry16 << 21;
+
+ // carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
+ // s8 += carry7;
+ // s7 -= carry7 * ((uint64_t) 1L << 21);
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ // carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
+ // s10 += carry9;
+ // s9 -= carry9 * ((uint64_t) 1L << 21);
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ // carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
+ // s12 += carry11;
+ // s11 -= carry11 * ((uint64_t) 1L << 21);
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+ // carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
+ // s14 += carry13;
+ // s13 -= carry13 * ((uint64_t) 1L << 21);
+ $carry13 = ($s13 + (1 << 20)) >> 21;
+ $s14 += $carry13;
+ $s13 -= $carry13 << 21;
+ // carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
+ // s16 += carry15;
+ // s15 -= carry15 * ((uint64_t) 1L << 21);
+ $carry15 = ($s15 + (1 << 20)) >> 21;
+ $s16 += $carry15;
+ $s15 -= $carry15 << 21;
+
+ // s5 += s17 * 666643;
+ // s6 += s17 * 470296;
+ // s7 += s17 * 654183;
+ // s8 -= s17 * 997805;
+ // s9 += s17 * 136657;
+ // s10 -= s17 * 683901;
+ $s5 += self::mul($s17, 666643, 20);
+ $s6 += self::mul($s17, 470296, 19);
+ $s7 += self::mul($s17, 654183, 20);
+ $s8 -= self::mul($s17, 997805, 20);
+ $s9 += self::mul($s17, 136657, 18);
+ $s10 -= self::mul($s17, 683901, 20);
+
+ // s4 += s16 * 666643;
+ // s5 += s16 * 470296;
+ // s6 += s16 * 654183;
+ // s7 -= s16 * 997805;
+ // s8 += s16 * 136657;
+ // s9 -= s16 * 683901;
+ $s4 += self::mul($s16, 666643, 20);
+ $s5 += self::mul($s16, 470296, 19);
+ $s6 += self::mul($s16, 654183, 20);
+ $s7 -= self::mul($s16, 997805, 20);
+ $s8 += self::mul($s16, 136657, 18);
+ $s9 -= self::mul($s16, 683901, 20);
+
+ // s3 += s15 * 666643;
+ // s4 += s15 * 470296;
+ // s5 += s15 * 654183;
+ // s6 -= s15 * 997805;
+ // s7 += s15 * 136657;
+ // s8 -= s15 * 683901;
+ $s3 += self::mul($s15, 666643, 20);
+ $s4 += self::mul($s15, 470296, 19);
+ $s5 += self::mul($s15, 654183, 20);
+ $s6 -= self::mul($s15, 997805, 20);
+ $s7 += self::mul($s15, 136657, 18);
+ $s8 -= self::mul($s15, 683901, 20);
+
+ // s2 += s14 * 666643;
+ // s3 += s14 * 470296;
+ // s4 += s14 * 654183;
+ // s5 -= s14 * 997805;
+ // s6 += s14 * 136657;
+ // s7 -= s14 * 683901;
+ $s2 += self::mul($s14, 666643, 20);
+ $s3 += self::mul($s14, 470296, 19);
+ $s4 += self::mul($s14, 654183, 20);
+ $s5 -= self::mul($s14, 997805, 20);
+ $s6 += self::mul($s14, 136657, 18);
+ $s7 -= self::mul($s14, 683901, 20);
+
+ // s1 += s13 * 666643;
+ // s2 += s13 * 470296;
+ // s3 += s13 * 654183;
+ // s4 -= s13 * 997805;
+ // s5 += s13 * 136657;
+ // s6 -= s13 * 683901;
+ $s1 += self::mul($s13, 666643, 20);
+ $s2 += self::mul($s13, 470296, 19);
+ $s3 += self::mul($s13, 654183, 20);
+ $s4 -= self::mul($s13, 997805, 20);
+ $s5 += self::mul($s13, 136657, 18);
+ $s6 -= self::mul($s13, 683901, 20);
+
+ // s0 += s12 * 666643;
+ // s1 += s12 * 470296;
+ // s2 += s12 * 654183;
+ // s3 -= s12 * 997805;
+ // s4 += s12 * 136657;
+ // s5 -= s12 * 683901;
+ // s12 = 0;
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+ $s12 = 0;
+
+ // carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
+ // s1 += carry0;
+ // s0 -= carry0 * ((uint64_t) 1L << 21);
+ $carry0 = ($s0 + (1 << 20)) >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ // carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
+ // s3 += carry2;
+ // s2 -= carry2 * ((uint64_t) 1L << 21);
+ $carry2 = ($s2 + (1 << 20)) >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ // carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
+ // s5 += carry4;
+ // s4 -= carry4 * ((uint64_t) 1L << 21);
+ $carry4 = ($s4 + (1 << 20)) >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ // carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
+ // s7 += carry6;
+ // s6 -= carry6 * ((uint64_t) 1L << 21);
+ $carry6 = ($s6 + (1 << 20)) >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ // carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
+ // s9 += carry8;
+ // s8 -= carry8 * ((uint64_t) 1L << 21);
+ $carry8 = ($s8 + (1 << 20)) >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ // carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
+ // s11 += carry10;
+ // s10 -= carry10 * ((uint64_t) 1L << 21);
+ $carry10 = ($s10 + (1 << 20)) >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+
+ // carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
+ // s2 += carry1;
+ // s1 -= carry1 * ((uint64_t) 1L << 21);
+ $carry1 = ($s1 + (1 << 20)) >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ // carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
+ // s4 += carry3;
+ // s3 -= carry3 * ((uint64_t) 1L << 21);
+ $carry3 = ($s3 + (1 << 20)) >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ // carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
+ // s6 += carry5;
+ // s5 -= carry5 * ((uint64_t) 1L << 21);
+ $carry5 = ($s5 + (1 << 20)) >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ // carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
+ // s8 += carry7;
+ // s7 -= carry7 * ((uint64_t) 1L << 21);
+ $carry7 = ($s7 + (1 << 20)) >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ // carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
+ // s10 += carry9;
+ // s9 -= carry9 * ((uint64_t) 1L << 21);
+ $carry9 = ($s9 + (1 << 20)) >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ // carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
+ // s12 += carry11;
+ // s11 -= carry11 * ((uint64_t) 1L << 21);
+ $carry11 = ($s11 + (1 << 20)) >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+
+ // s0 += s12 * 666643;
+ // s1 += s12 * 470296;
+ // s2 += s12 * 654183;
+ // s3 -= s12 * 997805;
+ // s4 += s12 * 136657;
+ // s5 -= s12 * 683901;
+ // s12 = 0;
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+ $s12 = 0;
+
+ // carry0 = s0 >> 21;
+ // s1 += carry0;
+ // s0 -= carry0 * ((uint64_t) 1L << 21);
+ $carry0 = $s0 >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ // carry1 = s1 >> 21;
+ // s2 += carry1;
+ // s1 -= carry1 * ((uint64_t) 1L << 21);
+ $carry1 = $s1 >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ // carry2 = s2 >> 21;
+ // s3 += carry2;
+ // s2 -= carry2 * ((uint64_t) 1L << 21);
+ $carry2 = $s2 >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ // carry3 = s3 >> 21;
+ // s4 += carry3;
+ // s3 -= carry3 * ((uint64_t) 1L << 21);
+ $carry3 = $s3 >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ // carry4 = s4 >> 21;
+ // s5 += carry4;
+ // s4 -= carry4 * ((uint64_t) 1L << 21);
+ $carry4 = $s4 >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ // carry5 = s5 >> 21;
+ // s6 += carry5;
+ // s5 -= carry5 * ((uint64_t) 1L << 21);
+ $carry5 = $s5 >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ // carry6 = s6 >> 21;
+ // s7 += carry6;
+ // s6 -= carry6 * ((uint64_t) 1L << 21);
+ $carry6 = $s6 >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ // carry7 = s7 >> 21;
+ // s8 += carry7;
+ // s7 -= carry7 * ((uint64_t) 1L << 21);
+ $carry7 = $s7 >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ // carry8 = s8 >> 21;
+ // s9 += carry8;
+ // s8 -= carry8 * ((uint64_t) 1L << 21);
+ $carry8 = $s8 >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ // carry9 = s9 >> 21;
+ // s10 += carry9;
+ // s9 -= carry9 * ((uint64_t) 1L << 21);
+ $carry9 = $s9 >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ // carry10 = s10 >> 21;
+ // s11 += carry10;
+ // s10 -= carry10 * ((uint64_t) 1L << 21);
+ $carry10 = $s10 >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+ // carry11 = s11 >> 21;
+ // s12 += carry11;
+ // s11 -= carry11 * ((uint64_t) 1L << 21);
+ $carry11 = $s11 >> 21;
+ $s12 += $carry11;
+ $s11 -= $carry11 << 21;
+
+ // s0 += s12 * 666643;
+ // s1 += s12 * 470296;
+ // s2 += s12 * 654183;
+ // s3 -= s12 * 997805;
+ // s4 += s12 * 136657;
+ // s5 -= s12 * 683901;
+ $s0 += self::mul($s12, 666643, 20);
+ $s1 += self::mul($s12, 470296, 19);
+ $s2 += self::mul($s12, 654183, 20);
+ $s3 -= self::mul($s12, 997805, 20);
+ $s4 += self::mul($s12, 136657, 18);
+ $s5 -= self::mul($s12, 683901, 20);
+
+ // carry0 = s0 >> 21;
+ // s1 += carry0;
+ // s0 -= carry0 * ((uint64_t) 1L << 21);
+ $carry0 = $s0 >> 21;
+ $s1 += $carry0;
+ $s0 -= $carry0 << 21;
+ // carry1 = s1 >> 21;
+ // s2 += carry1;
+ // s1 -= carry1 * ((uint64_t) 1L << 21);
+ $carry1 = $s1 >> 21;
+ $s2 += $carry1;
+ $s1 -= $carry1 << 21;
+ // carry2 = s2 >> 21;
+ // s3 += carry2;
+ // s2 -= carry2 * ((uint64_t) 1L << 21);
+ $carry2 = $s2 >> 21;
+ $s3 += $carry2;
+ $s2 -= $carry2 << 21;
+ // carry3 = s3 >> 21;
+ // s4 += carry3;
+ // s3 -= carry3 * ((uint64_t) 1L << 21);
+ $carry3 = $s3 >> 21;
+ $s4 += $carry3;
+ $s3 -= $carry3 << 21;
+ // carry4 = s4 >> 21;
+ // s5 += carry4;
+ // s4 -= carry4 * ((uint64_t) 1L << 21);
+ $carry4 = $s4 >> 21;
+ $s5 += $carry4;
+ $s4 -= $carry4 << 21;
+ // carry5 = s5 >> 21;
+ // s6 += carry5;
+ // s5 -= carry5 * ((uint64_t) 1L << 21);
+ $carry5 = $s5 >> 21;
+ $s6 += $carry5;
+ $s5 -= $carry5 << 21;
+ // carry6 = s6 >> 21;
+ // s7 += carry6;
+ // s6 -= carry6 * ((uint64_t) 1L << 21);
+ $carry6 = $s6 >> 21;
+ $s7 += $carry6;
+ $s6 -= $carry6 << 21;
+ // carry7 = s7 >> 21;
+ // s8 += carry7;
+ // s7 -= carry7 * ((uint64_t) 1L << 21);
+ $carry7 = $s7 >> 21;
+ $s8 += $carry7;
+ $s7 -= $carry7 << 21;
+ // carry8 = s8 >> 21;
+ // s9 += carry8;
+ // s8 -= carry8 * ((uint64_t) 1L << 21);
+ $carry8 = $s8 >> 21;
+ $s9 += $carry8;
+ $s8 -= $carry8 << 21;
+ // carry9 = s9 >> 21;
+ // s10 += carry9;
+ // s9 -= carry9 * ((uint64_t) 1L << 21);
+ $carry9 = $s9 >> 21;
+ $s10 += $carry9;
+ $s9 -= $carry9 << 21;
+ // carry10 = s10 >> 21;
+ // s11 += carry10;
+ // s10 -= carry10 * ((uint64_t) 1L << 21);
+ $carry10 = $s10 >> 21;
+ $s11 += $carry10;
+ $s10 -= $carry10 << 21;
+
+ $s = array_fill(0, 32, 0);
+ // s[0] = s0 >> 0;
+ $s[0] = $s0 >> 0;
+ // s[1] = s0 >> 8;
+ $s[1] = $s0 >> 8;
+ // s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5));
+ $s[2] = ($s0 >> 16) | ($s1 << 5);
+ // s[3] = s1 >> 3;
+ $s[3] = $s1 >> 3;
+ // s[4] = s1 >> 11;
+ $s[4] = $s1 >> 11;
+ // s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2));
+ $s[5] = ($s1 >> 19) | ($s2 << 2);
+ // s[6] = s2 >> 6;
+ $s[6] = $s2 >> 6;
+ // s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7));
+ $s[7] = ($s2 >> 14) | ($s3 << 7);
+ // s[8] = s3 >> 1;
+ $s[8] = $s3 >> 1;
+ // s[9] = s3 >> 9;
+ $s[9] = $s3 >> 9;
+ // s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4));
+ $s[10] = ($s3 >> 17) | ($s4 << 4);
+ // s[11] = s4 >> 4;
+ $s[11] = $s4 >> 4;
+ // s[12] = s4 >> 12;
+ $s[12] = $s4 >> 12;
+ // s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1));
+ $s[13] = ($s4 >> 20) | ($s5 << 1);
+ // s[14] = s5 >> 7;
+ $s[14] = $s5 >> 7;
+ // s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6));
+ $s[15] = ($s5 >> 15) | ($s6 << 6);
+ // s[16] = s6 >> 2;
+ $s[16] = $s6 >> 2;
+ // s[17] = s6 >> 10;
+ $s[17] = $s6 >> 10;
+ // s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3));
+ $s[18] = ($s6 >> 18) | ($s7 << 3);
+ // s[19] = s7 >> 5;
+ $s[19] = $s7 >> 5;
+ // s[20] = s7 >> 13;
+ $s[20] = $s7 >> 13;
+ // s[21] = s8 >> 0;
+ $s[21] = $s8 >> 0;
+ // s[22] = s8 >> 8;
+ $s[22] = $s8 >> 8;
+ // s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5));
+ $s[23] = ($s8 >> 16) | ($s9 << 5);
+ // s[24] = s9 >> 3;
+ $s[24] = $s9 >> 3;
+ // s[25] = s9 >> 11;
+ $s[25] = $s9 >> 11;
+ // s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2));
+ $s[26] = ($s9 >> 19) | ($s10 << 2);
+ // s[27] = s10 >> 6;
+ $s[27] = $s10 >> 6;
+ // s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7));
+ $s[28] = ($s10 >> 14) | ($s11 << 7);
+ // s[29] = s11 >> 1;
+ $s[29] = $s11 >> 1;
+ // s[30] = s11 >> 9;
+ $s[30] = $s11 >> 9;
+ // s[31] = s11 >> 17;
+ $s[31] = $s11 >> 17;
+ return self::intArrayToString($s);
+ }
+
+ /**
+ * @param string $s
+ * @return string
+ */
+ public static function sc25519_sq($s)
+ {
+ return self::sc25519_mul($s, $s);
+ }
+
+ /**
+ * @param string $s
+ * @param int $n
+ * @param string $a
+ * @return string
+ */
+ public static function sc25519_sqmul($s, $n, $a)
+ {
+ for ($i = 0; $i < $n; ++$i) {
+ $s = self::sc25519_sq($s);
+ }
+ return self::sc25519_mul($s, $a);
+ }
+
+ /**
+ * @param string $s
+ * @return string
+ */
+ public static function sc25519_invert($s)
+ {
+ $_10 = self::sc25519_sq($s);
+ $_11 = self::sc25519_mul($s, $_10);
+ $_100 = self::sc25519_mul($s, $_11);
+ $_1000 = self::sc25519_sq($_100);
+ $_1010 = self::sc25519_mul($_10, $_1000);
+ $_1011 = self::sc25519_mul($s, $_1010);
+ $_10000 = self::sc25519_sq($_1000);
+ $_10110 = self::sc25519_sq($_1011);
+ $_100000 = self::sc25519_mul($_1010, $_10110);
+ $_100110 = self::sc25519_mul($_10000, $_10110);
+ $_1000000 = self::sc25519_sq($_100000);
+ $_1010000 = self::sc25519_mul($_10000, $_1000000);
+ $_1010011 = self::sc25519_mul($_11, $_1010000);
+ $_1100011 = self::sc25519_mul($_10000, $_1010011);
+ $_1100111 = self::sc25519_mul($_100, $_1100011);
+ $_1101011 = self::sc25519_mul($_100, $_1100111);
+ $_10010011 = self::sc25519_mul($_1000000, $_1010011);
+ $_10010111 = self::sc25519_mul($_100, $_10010011);
+ $_10111101 = self::sc25519_mul($_100110, $_10010111);
+ $_11010011 = self::sc25519_mul($_10110, $_10111101);
+ $_11100111 = self::sc25519_mul($_1010000, $_10010111);
+ $_11101011 = self::sc25519_mul($_100, $_11100111);
+ $_11110101 = self::sc25519_mul($_1010, $_11101011);
+
+ $recip = self::sc25519_mul($_1011, $_11110101);
+ $recip = self::sc25519_sqmul($recip, 126, $_1010011);
+ $recip = self::sc25519_sqmul($recip, 9, $_10);
+ $recip = self::sc25519_mul($recip, $_11110101);
+ $recip = self::sc25519_sqmul($recip, 7, $_1100111);
+ $recip = self::sc25519_sqmul($recip, 9, $_11110101);
+ $recip = self::sc25519_sqmul($recip, 11, $_10111101);
+ $recip = self::sc25519_sqmul($recip, 8, $_11100111);
+ $recip = self::sc25519_sqmul($recip, 9, $_1101011);
+ $recip = self::sc25519_sqmul($recip, 6, $_1011);
+ $recip = self::sc25519_sqmul($recip, 14, $_10010011);
+ $recip = self::sc25519_sqmul($recip, 10, $_1100011);
+ $recip = self::sc25519_sqmul($recip, 9, $_10010111);
+ $recip = self::sc25519_sqmul($recip, 10, $_11110101);
+ $recip = self::sc25519_sqmul($recip, 8, $_11010011);
+ return self::sc25519_sqmul($recip, 8, $_11101011);
+ }
+
+ /**
+ * @param string $s
+ * @return string
+ */
+ public static function clamp($s)
+ {
+ $s_ = self::stringToIntArray($s);
+ $s_[0] &= 248;
+ $s_[31] |= 64;
+ $s_[31] &= 128;
+ return self::intArrayToString($s_);
+ }
+
+ /**
+ * Ensure limbs are less than 28 bits long to prevent float promotion.
+ *
+ * This uses a constant-time conditional swap under the hood.
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_normalize(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ $x = (PHP_INT_SIZE << 3) - 1; // 31 or 63
+
+ $g = self::fe_copy($f);
+ for ($i = 0; $i < 10; ++$i) {
+ $mask = -(($g[$i] >> $x) & 1);
+
+ /*
+ * Get two candidate normalized values for $g[$i], depending on the sign of $g[$i]:
+ */
+ $a = $g[$i] & 0x7ffffff;
+ $b = -((-$g[$i]) & 0x7ffffff);
+
+ /*
+ * Return the appropriate candidate value, based on the sign of the original input:
+ *
+ * The following is equivalent to this ternary:
+ *
+ * $g[$i] = (($g[$i] >> $x) & 1) ? $a : $b;
+ *
+ * Except what's written doesn't contain timing leaks.
+ */
+ $g[$i] = ($a ^ (($a ^ $b) & $mask));
+ }
+ return $g;
+ }
+}