Spaces:
Running
Running
/** | |
* 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; | |
} | |
} | |