summaryrefslogtreecommitdiffstats
path: root/vendor/paragonie/sodium_compat/src/Core/Ristretto255.php
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2024-05-27 13:08:29 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2024-05-27 13:08:29 +0200
commit75160b12821f7f4299cce7f0b69c83c1502ae071 (patch)
tree27e25e4ccaef45f0c58b22831164050d1af1d4db /vendor/paragonie/sodium_compat/src/Core/Ristretto255.php
parentprvi-commit (diff)
download1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.gz
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.bz2
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.lz
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.xz
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.zst
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.zip
Diffstat (limited to '')
-rw-r--r--vendor/paragonie/sodium_compat/src/Core/Ristretto255.php1414
1 files changed, 707 insertions, 707 deletions
diff --git a/vendor/paragonie/sodium_compat/src/Core/Ristretto255.php b/vendor/paragonie/sodium_compat/src/Core/Ristretto255.php
index 27dbbaa..2727260 100644
--- a/vendor/paragonie/sodium_compat/src/Core/Ristretto255.php
+++ b/vendor/paragonie/sodium_compat/src/Core/Ristretto255.php
@@ -1,707 +1,707 @@
-<?php
-
-/**
- * Class ParagonIE_Sodium_Core_Ristretto255
- */
-class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519
-{
- const crypto_core_ristretto255_HASHBYTES = 64;
- const HASH_SC_L = 48;
- const CORE_H2C_SHA256 = 1;
- const CORE_H2C_SHA512 = 2;
-
- /**
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @param int $b
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- */
- public static function fe_cneg(ParagonIE_Sodium_Core_Curve25519_Fe $f, $b)
- {
- $negf = self::fe_neg($f);
- return self::fe_cmov($f, $negf, $b);
- }
-
- /**
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return ParagonIE_Sodium_Core_Curve25519_Fe
- * @throws SodiumException
- */
- public static function fe_abs(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- return self::fe_cneg($f, self::fe_isnegative($f));
- }
-
- /**
- * Returns 0 if this field element results in all NUL bytes.
- *
- * @internal You should not use this directly from another application
- *
- * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
- * @return int
- * @throws SodiumException
- */
- public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
- {
- static $zero;
- if ($zero === null) {
- $zero = str_repeat("\x00", 32);
- }
- /** @var string $zero */
- $str = self::fe_tobytes($f);
-
- $d = 0;
- for ($i = 0; $i < 32; ++$i) {
- $d |= self::chrToInt($str[$i]);
- }
- return (($d - 1) >> 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;
- }
-}
+<?php
+
+/**
+ * Class ParagonIE_Sodium_Core_Ristretto255
+ */
+class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519
+{
+ const crypto_core_ristretto255_HASHBYTES = 64;
+ const HASH_SC_L = 48;
+ const CORE_H2C_SHA256 = 1;
+ const CORE_H2C_SHA512 = 2;
+
+ /**
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @param int $b
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ */
+ public static function fe_cneg(ParagonIE_Sodium_Core_Curve25519_Fe $f, $b)
+ {
+ $negf = self::fe_neg($f);
+ return self::fe_cmov($f, $negf, $b);
+ }
+
+ /**
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return ParagonIE_Sodium_Core_Curve25519_Fe
+ * @throws SodiumException
+ */
+ public static function fe_abs(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ return self::fe_cneg($f, self::fe_isnegative($f));
+ }
+
+ /**
+ * Returns 0 if this field element results in all NUL bytes.
+ *
+ * @internal You should not use this directly from another application
+ *
+ * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
+ * @return int
+ * @throws SodiumException
+ */
+ public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
+ {
+ static $zero;
+ if ($zero === null) {
+ $zero = str_repeat("\x00", 32);
+ }
+ /** @var string $zero */
+ $str = self::fe_tobytes($f);
+
+ $d = 0;
+ for ($i = 0; $i < 32; ++$i) {
+ $d |= self::chrToInt($str[$i]);
+ }
+ return (($d - 1) >> 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;
+ }
+}