diff -r 34716fd837a4 -r be944660c56a wp/wp-includes/sodium_compat/src/Core/Ristretto255.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wp/wp-includes/sodium_compat/src/Core/Ristretto255.php Wed Sep 21 18:19:35 2022 +0200 @@ -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; + } +}