From 30d411f482eb86ccb6d37645860589062fc59bb6 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Tue, 25 May 2021 13:55:58 +0000 Subject: [PATCH] Upgrade/Install: Update sodium_compat to v1.16.1. The latest version of sodium_compat includes polyfills for new features slated to land in PHP 8.1: https://paragonie.com/blog/2021/05/ristretto255-for-php-community It also fixes a race condition with the autoloader that caused an "undefined constant" error on some systems: https://github.com/paragonie/sodium_compat/issues/122 A full list of changes in this update can be found on GitHub: https://github.com/paragonie/sodium_compat/compare/v1.14.0...v1.16.1 Follow-up to [49741]. Props paragoninitiativeenterprises, oxyrealm. Fixes #53274. Built from https://develop.svn.wordpress.org/trunk@51002 git-svn-id: http://core.svn.wordpress.org/trunk@50611 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/sodium_compat/LICENSE | 37 +- wp-includes/sodium_compat/autoload.php | 9 +- wp-includes/sodium_compat/composer.json | 3 + wp-includes/sodium_compat/lib/php72compat.php | 3 + .../sodium_compat/lib/php72compat_const.php | 2 + .../sodium_compat/lib/ristretto255.php | 239 ++++ .../sodium_compat/lib/sodium_compat.php | 3 +- .../sodium_compat/lib/stream-xchacha20.php | 43 + wp-includes/sodium_compat/src/Compat.php | 397 +++++- .../sodium_compat/src/Core/BLAKE2b.php | 1 + .../sodium_compat/src/Core/Curve25519.php | 1136 ++++++++++++++++- .../sodium_compat/src/Core/Curve25519/H.php | 82 ++ .../sodium_compat/src/Core/Ed25519.php | 71 ++ .../sodium_compat/src/Core/Ristretto255.php | 707 ++++++++++ .../sodium_compat/src/Core/SipHash.php | 4 +- wp-includes/sodium_compat/src/Core/Util.php | 16 + .../sodium_compat/src/Core32/BLAKE2b.php | 1 + .../sodium_compat/src/Core32/Ed25519.php | 11 +- wp-includes/sodium_compat/src/File.php | 31 +- wp-includes/version.php | 2 +- 20 files changed, 2727 insertions(+), 71 deletions(-) create mode 100644 wp-includes/sodium_compat/lib/ristretto255.php create mode 100644 wp-includes/sodium_compat/lib/stream-xchacha20.php create mode 100644 wp-includes/sodium_compat/src/Core/Ristretto255.php diff --git a/wp-includes/sodium_compat/LICENSE b/wp-includes/sodium_compat/LICENSE index ce41e508c0..f5c62818e9 100644 --- a/wp-includes/sodium_compat/LICENSE +++ b/wp-includes/sodium_compat/LICENSE @@ -1,21 +1,16 @@ -/* - * ISC License - * - * Copyright (c) 2016-2019 - * Paragon Initiative Enterprises - * - * Copyright (c) 2013-2019 - * Frank Denis - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ \ No newline at end of file +ISC License + +Copyright (c) 2016-2021, Paragon Initiative Enterprises +Copyright (c) 2013-2019, Frank Denis + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/wp-includes/sodium_compat/autoload.php b/wp-includes/sodium_compat/autoload.php index d7c777b008..3f723bae7e 100644 --- a/wp-includes/sodium_compat/autoload.php +++ b/wp-includes/sodium_compat/autoload.php @@ -41,6 +41,9 @@ if (PHP_VERSION_ID < 70000) { require_once dirname(__FILE__) . '/autoload-php7.php'; } +/* Explicitly, always load the Compat class: */ +require_once dirname(__FILE__) . '/src/Compat.php'; + if (!class_exists('SodiumException', false)) { require_once dirname(__FILE__) . '/src/SodiumException.php'; } @@ -61,5 +64,9 @@ if (PHP_VERSION_ID < 70200 || !extension_loaded('sodium')) { } else { assert(class_exists('ParagonIE_Sodium_Compat')); } - require_once (dirname(__FILE__) . '/lib/php72compat.php'); + require_once(dirname(__FILE__) . '/lib/php72compat.php'); +} elseif (!function_exists('sodium_crypto_stream_xchacha20_xor')) { + // Older versions of {PHP, ext/sodium} will not define these + require_once(dirname(__FILE__) . '/lib/php72compat.php'); } +require_once(dirname(__FILE__) . '/lib/ristretto255.php'); diff --git a/wp-includes/sodium_compat/composer.json b/wp-includes/sodium_compat/composer.json index cf55d79042..21d6327ef3 100644 --- a/wp-includes/sodium_compat/composer.json +++ b/wp-includes/sodium_compat/composer.json @@ -56,6 +56,9 @@ "require-dev": { "phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9" }, + "scripts": { + "test": "phpunit" + }, "suggest": { "ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.", "ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." diff --git a/wp-includes/sodium_compat/lib/php72compat.php b/wp-includes/sodium_compat/lib/php72compat.php index fa8c37299f..10a061dfde 100644 --- a/wp-includes/sodium_compat/lib/php72compat.php +++ b/wp-includes/sodium_compat/lib/php72compat.php @@ -94,6 +94,8 @@ foreach (array( 'CRYPTO_SIGN_KEYPAIRBYTES', 'CRYPTO_STREAM_KEYBYTES', 'CRYPTO_STREAM_NONCEBYTES', + 'CRYPTO_STREAM_XCHACHA20_KEYBYTES', + 'CRYPTO_STREAM_XCHACHA20_NONCEBYTES', 'LIBRARY_MAJOR_VERSION', 'LIBRARY_MINOR_VERSION', 'LIBRARY_VERSION_MAJOR', @@ -1216,6 +1218,7 @@ if (!is_callable('sodium_crypto_stream_xor')) { return ParagonIE_Sodium_Compat::crypto_stream_xor($message, $nonce, $key); } } +require_once dirname(__FILE__) . '/stream-xchacha20.php'; if (!is_callable('sodium_hex2bin')) { /** * @see ParagonIE_Sodium_Compat::hex2bin() diff --git a/wp-includes/sodium_compat/lib/php72compat_const.php b/wp-includes/sodium_compat/lib/php72compat_const.php index 6a4247aa97..baa0f1e1cc 100644 --- a/wp-includes/sodium_compat/lib/php72compat_const.php +++ b/wp-includes/sodium_compat/lib/php72compat_const.php @@ -88,3 +88,5 @@ const SODIUM_CRYPTO_SIGN_SECRETKEYBYTES = 64; const SODIUM_CRYPTO_SIGN_KEYPAIRBYTES = 96; const SODIUM_CRYPTO_STREAM_KEYBYTES = 32; const SODIUM_CRYPTO_STREAM_NONCEBYTES = 24; +const SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32; +const SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24; diff --git a/wp-includes/sodium_compat/lib/ristretto255.php b/wp-includes/sodium_compat/lib/ristretto255.php new file mode 100644 index 0000000000..e5a7565dd6 --- /dev/null +++ b/wp-includes/sodium_compat/lib/ristretto255.php @@ -0,0 +1,239 @@ +> 31) & 1) === 1; + } + /** * The equivalent to the libsodium minor version we aim to be compatible * with (sans pwhash and memzero). @@ -3451,6 +3582,232 @@ class ParagonIE_Sodium_Compat return random_int(0, 65535); } + /** + * @param string $p + * @param bool $dontFallback + * @return bool + * @throws SodiumException + */ + public static function ristretto255_is_valid_point($p, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_is_valid_point($p); + } + try { + $r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p); + return $r['res'] === 0 && + ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1; + } catch (SodiumException $ex) { + if ($ex->getMessage() === 'S is not canonical') { + return false; + } + throw $ex; + } + } + + /** + * @param string $p + * @param string $q + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_add($p, $q, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_add($p, $q); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q); + } + + /** + * @param string $p + * @param string $q + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_sub($p, $q, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_sub($p, $q); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q); + } + + /** + * @param string $r + * @param bool $dontFallback + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_from_hash($r, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_from_hash($r); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r); + } + + /** + * @param bool $dontFallback + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_random($dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_random(); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random(); + } + + /** + * @param bool $dontFallback + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_scalar_random($dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_random(); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random(); + } + + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_invert($s, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_invert($s); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s); + } + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_negate($s, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_negate($s); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s); + } + + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_complement($s, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_complement($s); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s); + } + + /** + * @param string $x + * @param string $y + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_add($x, $y, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_add($x, $y); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y); + } + + /** + * @param string $x + * @param string $y + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_sub($x, $y, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_sub($x, $y); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y); + } + + /** + * @param string $x + * @param string $y + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_mul($x, $y, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_mul($x, $y); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y); + } + + /** + * @param string $n + * @param string $p + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255($n, $p, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_scalarmult_ristretto255($n, $p); + } + return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p); + } + + /** + * @param string $n + * @param string $p + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255_base($n, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_scalarmult_ristretto255_base($n); + } + return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n); + } + + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_reduce($s, $dontFallback = false) + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_reduce($s); + } + return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s); + } + /** * Runtime testing method for 32-bit platforms. * @@ -3487,6 +3844,36 @@ class ParagonIE_Sodium_Compat return $diff < $maxTimeout; } + /** + * Add two numbers (little-endian unsigned), storing the value in the first + * parameter. + * + * This mutates $val. + * + * @param string $val + * @param string $addv + * @return void + * @throws SodiumException + */ + public static function sub(&$val, $addv) + { + $val_len = ParagonIE_Sodium_Core_Util::strlen($val); + $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv); + if ($val_len !== $addv_len) { + throw new SodiumException('values must have the same length'); + } + $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val); + $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv); + + $c = 0; + for ($i = 0; $i < $val_len; $i++) { + $c = ($A[$i] - $B[$i] - $c); + $A[$i] = ($c & 0xff); + $c = ($c >> 8) & 1; + } + $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); + } + /** * This emulates libsodium's version_string() function, except ours is * prefixed with 'polyfill-'. diff --git a/wp-includes/sodium_compat/src/Core/BLAKE2b.php b/wp-includes/sodium_compat/src/Core/BLAKE2b.php index 930a0ede3d..5251bafe71 100644 --- a/wp-includes/sodium_compat/src/Core/BLAKE2b.php +++ b/wp-includes/sodium_compat/src/Core/BLAKE2b.php @@ -644,6 +644,7 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util * * @param string $str * @return SplFixedArray + * @psalm-suppress MixedArgumentTypeCoercion */ public static function stringToSplFixedArray($str = '') { diff --git a/wp-includes/sodium_compat/src/Core/Curve25519.php b/wp-includes/sodium_compat/src/Core/Curve25519.php index 4402f91703..0ea25177b2 100644 --- a/wp-includes/sodium_compat/src/Core/Curve25519.php +++ b/wp-includes/sodium_compat/src/Core/Curve25519.php @@ -86,9 +86,8 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu $h = array(); $b *= -1; for ($i = 0; $i < 10; ++$i) { - /** @var int $x */ $x = (($f[$i] ^ $g[$i]) & $b); - $h[$i] = (int) ((int) ($f[$i]) ^ $x); + $h[$i] = ($f[$i]) ^ $x; } return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); } @@ -701,7 +700,7 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu $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, 25); + $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); @@ -710,7 +709,7 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu $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, 25); + $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); @@ -718,15 +717,15 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu $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, 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, 24); - $f2f8_38 = self::mul($f8_19, $f2_2, 26); - $f2f9_38 = self::mul($f9_38, $f2, 25); - $f3f3_2 = self::mul($f3_2, $f3, 24); + $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); @@ -1585,9 +1584,9 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) { return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( - $p->X, - $p->Y, - $p->Z + self::fe_copy($p->X), + self::fe_copy($p->Y), + self::fe_copy($p->Z) ); } @@ -1644,7 +1643,7 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu */ public static function equal($b, $c) { - return (int) ((($b ^ $c) - 1 & 0xffffffff) >> 31); + return (int) ((($b ^ $c) - 1) >> 31) & 1; } /** @@ -1658,7 +1657,7 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu public static function negative($char) { if (is_int($char)) { - return $char < 0 ? 1 : 0; + return ($char >> 63) & 1; } $x = self::chrToInt(self::substr($char, 0, 1)); return (int) ($x >> 63); @@ -1683,12 +1682,78 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu 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->yplusx, $u->yplusx, $b), self::fe_cmov($t->yminusx, $u->yminusx, $b), - self::fe_cmov($t->xy2d, $u->xy2d, $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 * @@ -1925,6 +1990,145 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu 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 * @@ -2999,4 +3203,904 @@ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Cu # 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_); + } } diff --git a/wp-includes/sodium_compat/src/Core/Curve25519/H.php b/wp-includes/sodium_compat/src/Core/Curve25519/H.php index 37ad497dc3..a2fbbf9f69 100644 --- a/wp-includes/sodium_compat/src/Core/Curve25519/H.php +++ b/wp-includes/sodium_compat/src/Core/Curve25519/H.php @@ -1464,4 +1464,86 @@ class ParagonIE_Sodium_Core_Curve25519_H extends ParagonIE_Sodium_Core_Util 326686, 11406482 ); + + /** + * 1 / sqrt(a - d) + * + * @var array + */ + protected static $invsqrtamd = array( + 6111485, + 4156064, + -27798727, + 12243468, + -25904040, + 120897, + 20826367, + -7060776, + 6093568, + -1986012 + ); + + /** + * sqrt(ad - 1) with a = -1 (mod p) + * + * @var array + */ + protected static $sqrtadm1 = array( + 24849947, + -153582, + -23613485, + 6347715, + -21072328, + -667138, + -25271143, + -15367704, + -870347, + 14525639 + ); + + /** + * 1 - d ^ 2 + * + * @var array + */ + protected static $onemsqd = array( + 6275446, + -16617371, + -22938544, + -3773710, + 11667077, + 7397348, + -27922721, + 1766195, + -24433858, + 672203 + ); + + /** + * (d - 1) ^ 2 + * @var array + */ + protected static $sqdmone = array( + 15551795, + -11097455, + -13425098, + -10125071, + -11896535, + 10178284, + -26634327, + 4729244, + -5282110, + -10116402 + ); + + + /* + * 2^252+27742317777372353535851937790883648493 + static const unsigned char L[] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 + }; + */ + const L = "\xed\xd3\xf5\x5c\x1a\x63\x12\x58\xd6\x9c\xf7\xa2\xde\xf9\xde\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"; } diff --git a/wp-includes/sodium_compat/src/Core/Ed25519.php b/wp-includes/sodium_compat/src/Core/Ed25519.php index 16ae1d2e88..f135b1c611 100644 --- a/wp-includes/sodium_compat/src/Core/Ed25519.php +++ b/wp-includes/sodium_compat/src/Core/Ed25519.php @@ -11,6 +11,7 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve { const KEYPAIR_BYTES = 96; const SEED_BYTES = 32; + const SCALAR_BYTES = 32; /** * @internal You should not use this directly from another application @@ -477,4 +478,74 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve } return false; } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function scalar_complement($s) + { + $t_ = self::L . str_repeat("\x00", 32); + sodium_increment($t_); + $s_ = $s . str_repeat("\x00", 32); + ParagonIE_Sodium_Compat::sub($t_, $s_); + return self::sc_reduce($t_); + } + + /** + * @return string + * @throws SodiumException + */ + public static function scalar_random() + { + do { + $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES); + $r[self::SCALAR_BYTES - 1] = self::intToChr( + self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f + ); + } while ( + !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r) + ); + return $r; + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function scalar_negate($s) + { + $t_ = self::L . str_repeat("\x00", 32) ; + $s_ = $s . str_repeat("\x00", 32) ; + ParagonIE_Sodium_Compat::sub($t_, $s_); + return self::sc_reduce($t_); + } + + /** + * @param string $a + * @param string $b + * @return string + * @throws SodiumException + */ + public static function scalar_add($a, $b) + { + $a_ = $a . str_repeat("\x00", 32); + $b_ = $b . str_repeat("\x00", 32); + ParagonIE_Sodium_Compat::add($a_, $b_); + return self::sc_reduce($a_); + } + + /** + * @param string $x + * @param string $y + * @return string + * @throws SodiumException + */ + public static function scalar_sub($x, $y) + { + $yn = self::scalar_negate($y); + return self::scalar_add($x, $yn); + } } diff --git a/wp-includes/sodium_compat/src/Core/Ristretto255.php b/wp-includes/sodium_compat/src/Core/Ristretto255.php new file mode 100644 index 0000000000..2727260d21 --- /dev/null +++ b/wp-includes/sodium_compat/src/Core/Ristretto255.php @@ -0,0 +1,707 @@ +> 31) & 1; + } + + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Fe $u + * @param ParagonIE_Sodium_Core_Curve25519_Fe $v + * @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int} + * + * @throws SodiumException + */ + public static function ristretto255_sqrt_ratio_m1( + ParagonIE_Sodium_Core_Curve25519_Fe $u, + ParagonIE_Sodium_Core_Curve25519_Fe $v + ) { + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1); + + $v3 = self::fe_mul( + self::fe_sq($v), + $v + ); /* v3 = v^3 */ + $x = self::fe_mul( + self::fe_mul( + self::fe_sq($v3), + $u + ), + $v + ); /* x = uv^7 */ + + $x = self::fe_mul( + self::fe_mul( + self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */ + $v3 + ), + $u + ); /* x = uv^3(uv^7)^((q-5)/8) */ + + $vxx = self::fe_mul( + self::fe_sq($x), + $v + ); /* vx^2 */ + + $m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */ + $p_root_check = self::fe_add($vxx, $u); /* vx^2+u */ + $f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */ + $f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */ + + $has_m_root = self::fe_iszero($m_root_check); + $has_p_root = self::fe_iszero($p_root_check); + $has_f_root = self::fe_iszero($f_root_check); + + $x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */ + + $x = self::fe_abs( + self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root) + ); + return array( + 'x' => $x, + 'nonsquare' => $has_m_root | $has_p_root + ); + } + + /** + * @param string $s + * @return int + * @throws SodiumException + */ + public static function ristretto255_point_is_canonical($s) + { + $c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f; + for ($i = 30; $i > 0; --$i) { + $c |= self::chrToInt($s[$i]) ^ 0xff; + } + $c = ($c - 1) >> 8; + $d = (0xed - 1 - self::chrToInt($s[0])) >> 8; + $e = self::chrToInt($s[31]) >> 7; + + return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1); + } + + /** + * @param string $s + * @param bool $skipCanonicalCheck + * @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int} + * @throws SodiumException + */ + public static function ristretto255_frombytes($s, $skipCanonicalCheck = false) + { + if (!$skipCanonicalCheck) { + if (!self::ristretto255_point_is_canonical($s)) { + throw new SodiumException('S is not canonical'); + } + } + + $s_ = self::fe_frombytes($s); + $ss = self::fe_sq($s_); /* ss = s^2 */ + + $u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */ + $u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */ + + $u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */ + $u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */ + + $v = self::fe_mul( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d), + $u1u1 + ); /* v = d*u1^2 */ + $v = self::fe_neg($v); /* v = -d*u1^2 */ + $v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */ + $v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */ + + // fe25519_1(one); + // notsquare = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2); + $one = self::fe_1(); + $result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2); + $inv_sqrt = $result['x']; + $notsquare = $result['nonsquare']; + + $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); + + $h->X = self::fe_mul($inv_sqrt, $u2); + $h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v); + + $h->X = self::fe_mul($h->X, $s_); + $h->X = self::fe_abs( + self::fe_add($h->X, $h->X) + ); + $h->Y = self::fe_mul($u1, $h->Y); + $h->Z = self::fe_1(); + $h->T = self::fe_mul($h->X, $h->Y); + + $res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y)); + return array('h' => $h, 'res' => $res); + } + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h + * @return string + * @throws SodiumException + */ + public static function ristretto255_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h) + { + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1); + $invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$invsqrtamd); + + $u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */ + $zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */ + $u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */ + $u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */ + + $u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */ + $one = self::fe_1(); + + // fe25519_1(one); + // (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2); + $result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2); + $inv_sqrt = $result['x']; + + $den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */ + $den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */ + $z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */ + + $ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */ + $iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */ + $eden = self::fe_mul($den1, $invsqrtamd); + + $t_z_inv = self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */ + $rotate = self::fe_isnegative($t_z_inv); + + $x_ = self::fe_copy($h->X); + $y_ = self::fe_copy($h->Y); + $den_inv = self::fe_copy($den2); + + $x_ = self::fe_cmov($x_, $iy, $rotate); + $y_ = self::fe_cmov($y_, $ix, $rotate); + $den_inv = self::fe_cmov($den_inv, $eden, $rotate); + + $x_z_inv = self::fe_mul($x_, $z_inv); + $y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv)); + + + // fe25519_sub(s_, h->Z, y_); + // fe25519_mul(s_, den_inv, s_); + // fe25519_abs(s_, s_); + // fe25519_tobytes(s, s_); + return self::fe_tobytes( + self::fe_abs( + self::fe_mul( + $den_inv, + self::fe_sub($h->Z, $y_) + ) + ) + ); + } + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Fe $t + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + * + * @throws SodiumException + */ + public static function ristretto255_elligator(ParagonIE_Sodium_Core_Curve25519_Fe $t) + { + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1); + $onemsqd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$onemsqd); + $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d); + $sqdmone = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqdmone); + $sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtadm1); + + $one = self::fe_1(); + $r = self::fe_mul($sqrtm1, self::fe_sq($t)); /* r = sqrt(-1)*t^2 */ + $u = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */ + $c = self::fe_neg(self::fe_1()); /* c = -1 */ + $rpd = self::fe_add($r, $d); /* rpd = r+d */ + + $v = self::fe_mul( + self::fe_sub( + $c, + self::fe_mul($r, $d) + ), + $rpd + ); /* v = (c-r*d)*(r+d) */ + + $result = self::ristretto255_sqrt_ratio_m1($u, $v); + $s = $result['x']; + $wasnt_square = 1 - $result['nonsquare']; + + $s_prime = self::fe_neg( + self::fe_abs( + self::fe_mul($s, $t) + ) + ); /* s_prime = -|s*t| */ + $s = self::fe_cmov($s, $s_prime, $wasnt_square); + $c = self::fe_cmov($c, $r, $wasnt_square); + + // fe25519_sub(n, r, one); /* n = r-1 */ + // fe25519_mul(n, n, c); /* n = c*(r-1) */ + // fe25519_mul(n, n, ed25519_sqdmone); /* n = c*(r-1)*(d-1)^2 */ + // fe25519_sub(n, n, v); /* n = c*(r-1)*(d-1)^2-v */ + $n = self::fe_sub( + self::fe_mul( + self::fe_mul( + self::fe_sub($r, $one), + $c + ), + $sqdmone + ), + $v + ); /* n = c*(r-1)*(d-1)^2-v */ + + $w0 = self::fe_mul( + self::fe_add($s, $s), + $v + ); /* w0 = 2s*v */ + + $w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */ + $ss = self::fe_sq($s); /* ss = s^2 */ + $w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */ + $w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */ + + return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( + self::fe_mul($w0, $w3), + self::fe_mul($w2, $w1), + self::fe_mul($w1, $w3), + self::fe_mul($w0, $w2) + ); + } + + /** + * @param string $h + * @return string + * @throws SodiumException + */ + public static function ristretto255_from_hash($h) + { + if (self::strlen($h) !== 64) { + throw new SodiumException('Hash must be 64 bytes'); + } + //fe25519_frombytes(r0, h); + //fe25519_frombytes(r1, h + 32); + $r0 = self::fe_frombytes(self::substr($h, 0, 32)); + $r1 = self::fe_frombytes(self::substr($h, 32, 32)); + + //ristretto255_elligator(&p0, r0); + //ristretto255_elligator(&p1, r1); + $p0 = self::ristretto255_elligator($r0); + $p1 = self::ristretto255_elligator($r1); + + //ge25519_p3_to_cached(&p1_cached, &p1); + //ge25519_add_cached(&p_p1p1, &p0, &p1_cached); + $p_p1p1 = self::ge_add( + $p0, + self::ge_p3_to_cached($p1) + ); + + //ge25519_p1p1_to_p3(&p, &p_p1p1); + //ristretto255_p3_tobytes(s, &p); + return self::ristretto255_p3_tobytes( + self::ge_p1p1_to_p3($p_p1p1) + ); + } + + /** + * @param string $p + * @return int + * @throws SodiumException + */ + public static function is_valid_point($p) + { + $result = self::ristretto255_frombytes($p); + if ($result['res'] !== 0) { + return 0; + } + return 1; + } + + /** + * @param string $p + * @param string $q + * @return string + * @throws SodiumException + */ + public static function ristretto255_add($p, $q) + { + $p_res = self::ristretto255_frombytes($p); + $q_res = self::ristretto255_frombytes($q); + if ($p_res['res'] !== 0 || $q_res['res'] !== 0) { + throw new SodiumException('Could not add points'); + } + $p_p3 = $p_res['h']; + $q_p3 = $q_res['h']; + $q_cached = self::ge_p3_to_cached($q_p3); + $r_p1p1 = self::ge_add($p_p3, $q_cached); + $r_p3 = self::ge_p1p1_to_p3($r_p1p1); + return self::ristretto255_p3_tobytes($r_p3); + } + + /** + * @param string $p + * @param string $q + * @return string + * @throws SodiumException + */ + public static function ristretto255_sub($p, $q) + { + $p_res = self::ristretto255_frombytes($p); + $q_res = self::ristretto255_frombytes($q); + if ($p_res['res'] !== 0 || $q_res['res'] !== 0) { + throw new SodiumException('Could not add points'); + } + $p_p3 = $p_res['h']; + $q_p3 = $q_res['h']; + $q_cached = self::ge_p3_to_cached($q_p3); + $r_p1p1 = self::ge_sub($p_p3, $q_cached); + $r_p3 = self::ge_p1p1_to_p3($r_p1p1); + return self::ristretto255_p3_tobytes($r_p3); + } + + + /** + * @param int $hLen + * @param ?string $ctx + * @param string $msg + * @return string + * @throws SodiumException + * @psalm-suppress PossiblyInvalidArgument hash API + */ + protected static function h2c_string_to_hash_sha256($hLen, $ctx, $msg) + { + $h = array_fill(0, $hLen, 0); + $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0; + if ($hLen > 0xff) { + throw new SodiumException('Hash must be less than 256 bytes'); + } + + if ($ctx_len > 0xff) { + $st = hash_init('sha256'); + self::hash_update($st, "H2C-OVERSIZE-DST-"); + self::hash_update($st, $ctx); + $ctx = hash_final($st, true); + $ctx_len = 32; + } + $t = array(0, $hLen, 0); + $ux = str_repeat("\0", 64); + $st = hash_init('sha256'); + self::hash_update($st, $ux); + self::hash_update($st, $msg); + self::hash_update($st, self::intArrayToString($t)); + self::hash_update($st, $ctx); + self::hash_update($st, self::intToChr($ctx_len)); + $u0 = hash_final($st, true); + + for ($i = 0; $i < $hLen; $i += 64) { + $ux = self::xorStrings($ux, $u0); + ++$t[2]; + $st = hash_init('sha256'); + self::hash_update($st, $ux); + self::hash_update($st, self::intToChr($t[2])); + self::hash_update($st, $ctx); + self::hash_update($st, self::intToChr($ctx_len)); + $ux = hash_final($st, true); + $amount = min($hLen - $i, 64); + for ($j = 0; $j < $amount; ++$j) { + $h[$i + $j] = self::chrToInt($ux[$i]); + } + } + return self::intArrayToString(array_slice($h, 0, $hLen)); + } + + /** + * @param int $hLen + * @param ?string $ctx + * @param string $msg + * @return string + * @throws SodiumException + * @psalm-suppress PossiblyInvalidArgument hash API + */ + protected static function h2c_string_to_hash_sha512($hLen, $ctx, $msg) + { + $h = array_fill(0, $hLen, 0); + $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0; + if ($hLen > 0xff) { + throw new SodiumException('Hash must be less than 256 bytes'); + } + + if ($ctx_len > 0xff) { + $st = hash_init('sha256'); + self::hash_update($st, "H2C-OVERSIZE-DST-"); + self::hash_update($st, $ctx); + $ctx = hash_final($st, true); + $ctx_len = 32; + } + $t = array(0, $hLen, 0); + $ux = str_repeat("\0", 128); + $st = hash_init('sha512'); + self::hash_update($st, $ux); + self::hash_update($st, $msg); + self::hash_update($st, self::intArrayToString($t)); + self::hash_update($st, $ctx); + self::hash_update($st, self::intToChr($ctx_len)); + $u0 = hash_final($st, true); + + for ($i = 0; $i < $hLen; $i += 128) { + $ux = self::xorStrings($ux, $u0); + ++$t[2]; + $st = hash_init('sha512'); + self::hash_update($st, $ux); + self::hash_update($st, self::intToChr($t[2])); + self::hash_update($st, $ctx); + self::hash_update($st, self::intToChr($ctx_len)); + $ux = hash_final($st, true); + $amount = min($hLen - $i, 128); + for ($j = 0; $j < $amount; ++$j) { + $h[$i + $j] = self::chrToInt($ux[$i]); + } + } + return self::intArrayToString(array_slice($h, 0, $hLen)); + } + + /** + * @param int $hLen + * @param ?string $ctx + * @param string $msg + * @param int $hash_alg + * @return string + * @throws SodiumException + */ + public static function h2c_string_to_hash($hLen, $ctx, $msg, $hash_alg) + { + switch ($hash_alg) { + case self::CORE_H2C_SHA256: + return self::h2c_string_to_hash_sha256($hLen, $ctx, $msg); + case self::CORE_H2C_SHA512: + return self::h2c_string_to_hash_sha512($hLen, $ctx, $msg); + default: + throw new SodiumException('Invalid H2C hash algorithm'); + } + } + + /** + * @param ?string $ctx + * @param string $msg + * @param int $hash_alg + * @return string + * @throws SodiumException + */ + protected static function _string_to_element($ctx, $msg, $hash_alg) + { + return self::ristretto255_from_hash( + self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg) + ); + } + + /** + * @return string + * @throws SodiumException + * @throws Exception + */ + public static function ristretto255_random() + { + return self::ristretto255_from_hash( + ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES) + ); + } + + /** + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_random() + { + return self::scalar_random(); + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_complement($s) + { + return self::scalar_complement($s); + } + + + /** + * @param string $s + * @return string + */ + public static function ristretto255_scalar_invert($s) + { + return self::sc25519_invert($s); + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_negate($s) + { + return self::scalar_negate($s); + } + + /** + * @param string $x + * @param string $y + * @return string + */ + public static function ristretto255_scalar_add($x, $y) + { + return self::scalar_add($x, $y); + } + + /** + * @param string $x + * @param string $y + * @return string + */ + public static function ristretto255_scalar_sub($x, $y) + { + return self::scalar_sub($x, $y); + } + + /** + * @param string $x + * @param string $y + * @return string + */ + public static function ristretto255_scalar_mul($x, $y) + { + return self::sc25519_mul($x, $y); + } + + /** + * @param string $ctx + * @param string $msg + * @param int $hash_alg + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_from_string($ctx, $msg, $hash_alg) + { + $h = array_fill(0, 64, 0); + $h_be = self::stringToIntArray( + self::h2c_string_to_hash( + self::HASH_SC_L, $ctx, $msg, $hash_alg + ) + ); + + for ($i = 0; $i < self::HASH_SC_L; ++$i) { + $h[$i] = $h_be[self::HASH_SC_L - 1 - $i]; + } + return self::ristretto255_scalar_reduce(self::intArrayToString($h)); + } + + /** + * @param string $s + * @return string + */ + public static function ristretto255_scalar_reduce($s) + { + return self::sc_reduce($s); + } + + /** + * @param string $n + * @param string $p + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255($n, $p) + { + if (self::strlen($n) !== 32) { + throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.'); + } + if (self::strlen($p) !== 32) { + throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.'); + } + $result = self::ristretto255_frombytes($p); + if ($result['res'] !== 0) { + throw new SodiumException('Could not multiply points'); + } + $P = $result['h']; + + $t = self::stringToIntArray($n); + $t[31] &= 0x7f; + $Q = self::ge_scalarmult(self::intArrayToString($t), $P); + $q = self::ristretto255_p3_tobytes($Q); + if (ParagonIE_Sodium_Compat::is_zero($q)) { + throw new SodiumException('An unknown error has occurred'); + } + return $q; + } + + /** + * @param string $n + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255_base($n) + { + $t = self::stringToIntArray($n); + $t[31] &= 0x7f; + $Q = self::ge_scalarmult_base(self::intArrayToString($t)); + $q = self::ristretto255_p3_tobytes($Q); + if (ParagonIE_Sodium_Compat::is_zero($q)) { + throw new SodiumException('An unknown error has occurred'); + } + return $q; + } +} diff --git a/wp-includes/sodium_compat/src/Core/SipHash.php b/wp-includes/sodium_compat/src/Core/SipHash.php index 542b4cc2e4..90c3b69612 100644 --- a/wp-includes/sodium_compat/src/Core/SipHash.php +++ b/wp-includes/sodium_compat/src/Core/SipHash.php @@ -14,8 +14,8 @@ class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util /** * @internal You should not use this directly from another application * - * @param array $v - * @return array + * @param int[] $v + * @return int[] * */ public static function sipRound(array $v) diff --git a/wp-includes/sodium_compat/src/Core/Util.php b/wp-includes/sodium_compat/src/Core/Util.php index 3bb4dafb30..007f064b2a 100644 --- a/wp-includes/sodium_compat/src/Core/Util.php +++ b/wp-includes/sodium_compat/src/Core/Util.php @@ -286,6 +286,22 @@ abstract class ParagonIE_Sodium_Core_Util return $left === $right; } + /** + * Catch hash_update() failures and throw instead of silently proceding + * + * @param HashContext|resource &$hs + * @param string $data + * @return void + * @throws SodiumException + * @psalm-suppress PossiblyInvalidArgument + */ + protected static function hash_update(&$hs, $data) + { + if (!hash_update($hs, $data)) { + throw new SodiumException('hash_update() failed'); + } + } + /** * Convert a hexadecimal string into a binary string without cache-timing * leaks diff --git a/wp-includes/sodium_compat/src/Core32/BLAKE2b.php b/wp-includes/sodium_compat/src/Core32/BLAKE2b.php index 5b30ade060..0fed21a25f 100644 --- a/wp-includes/sodium_compat/src/Core32/BLAKE2b.php +++ b/wp-includes/sodium_compat/src/Core32/BLAKE2b.php @@ -577,6 +577,7 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti * * @param string $str * @return SplFixedArray + * @psalm-suppress MixedArgumentTypeCoercion */ public static function stringToSplFixedArray($str = '') { diff --git a/wp-includes/sodium_compat/src/Core32/Ed25519.php b/wp-includes/sodium_compat/src/Core32/Ed25519.php index 927d11e109..3cb6422547 100644 --- a/wp-includes/sodium_compat/src/Core32/Ed25519.php +++ b/wp-includes/sodium_compat/src/Core32/Ed25519.php @@ -207,6 +207,7 @@ abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_C * @return string * @throws SodiumException * @throws TypeError + * @psalm-suppress PossiblyInvalidArgument */ public static function sign_detached($message, $sk) { @@ -224,8 +225,8 @@ abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_C # crypto_hash_sha512_update(&hs, m, mlen); # crypto_hash_sha512_final(&hs, nonce); $hs = hash_init('sha512'); - hash_update($hs, self::substr($az, 32, 32)); - hash_update($hs, $message); + self::hash_update($hs, self::substr($az, 32, 32)); + self::hash_update($hs, $message); $nonceHash = hash_final($hs, true); # memmove(sig + 32, sk + 32, 32); @@ -244,9 +245,9 @@ abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_C # crypto_hash_sha512_update(&hs, m, mlen); # crypto_hash_sha512_final(&hs, hram); $hs = hash_init('sha512'); - hash_update($hs, self::substr($sig, 0, 32)); - hash_update($hs, self::substr($pk, 0, 32)); - hash_update($hs, $message); + self::hash_update($hs, self::substr($sig, 0, 32)); + self::hash_update($hs, self::substr($pk, 0, 32)); + self::hash_update($hs, $message); $hramHash = hash_final($hs, true); # sc_reduce(hram); diff --git a/wp-includes/sodium_compat/src/File.php b/wp-includes/sodium_compat/src/File.php index 867da3b9a9..d71bc7e5ad 100644 --- a/wp-includes/sodium_compat/src/File.php +++ b/wp-includes/sodium_compat/src/File.php @@ -597,7 +597,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); $hs = hash_init('sha512'); - hash_update($hs, self::substr($az, 32, 32)); + self::hash_update($hs, self::substr($az, 32, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); @@ -616,8 +616,8 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util ); $hs = hash_init('sha512'); - hash_update($hs, self::substr($sig, 0, 32)); - hash_update($hs, self::substr($pk, 0, 32)); + self::hash_update($hs, self::substr($sig, 0, 32)); + self::hash_update($hs, self::substr($pk, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); @@ -728,8 +728,8 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util $A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey); $hs = hash_init('sha512'); - hash_update($hs, self::substr($sig, 0, 32)); - hash_update($hs, self::substr($publicKey, 0, 32)); + self::hash_update($hs, self::substr($sig, 0, 32)); + self::hash_update($hs, self::substr($publicKey, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); /** @var string $hDigest */ @@ -1083,7 +1083,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util * Update a hash context with the contents of a file, without * loading the entire file into memory. * - * @param resource|object $hash + * @param resource|HashContext $hash * @param resource $fp * @param int $size * @return resource|object Resource on PHP < 7.2, HashContext object on PHP >= 7.2 @@ -1133,7 +1133,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util } /** @var string $message */ /** @psalm-suppress InvalidArgument */ - hash_update($hash, $message); + self::hash_update($hash, $message); } // Reset file pointer's position fseek($fp, $originalPosition, SEEK_SET); @@ -1175,7 +1175,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); $hs = hash_init('sha512'); - hash_update($hs, self::substr($az, 32, 32)); + self::hash_update($hs, self::substr($az, 32, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); @@ -1194,8 +1194,8 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util ); $hs = hash_init('sha512'); - hash_update($hs, self::substr($sig, 0, 32)); - hash_update($hs, self::substr($pk, 0, 32)); + self::hash_update($hs, self::substr($sig, 0, 32)); + self::hash_update($hs, self::substr($pk, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); @@ -1278,8 +1278,8 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util $A = ParagonIE_Sodium_Core32_Ed25519::ge_frombytes_negate_vartime($publicKey); $hs = hash_init('sha512'); - hash_update($hs, self::substr($sig, 0, 32)); - hash_update($hs, self::substr($publicKey, 0, 32)); + self::hash_update($hs, self::substr($sig, 0, 32)); + self::hash_update($hs, self::substr($publicKey, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); /** @var string $hDigest */ @@ -1527,12 +1527,6 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util /** @var int $pos */ $pos = self::ftell($ifp); - /** @var int $iter */ - $iter = 1; - - /** @var int $incr */ - $incr = self::BUFFER_SIZE >> 6; - while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE @@ -1543,7 +1537,6 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util } $state->update($ciphertext); $mlen -= $blockSize; - $iter += $incr; } $res = ParagonIE_Sodium_Core32_Util::verify_16($tag, $state->finish()); diff --git a/wp-includes/version.php b/wp-includes/version.php index 882ec44bb1..8470727fa5 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.8-alpha-51001'; +$wp_version = '5.8-alpha-51002'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.