<?php
/**
* Class SodiumCompatTest
*/
class Ristretto255CompatTest extends PHPUnit_Framework_TestCase
{
/**
* @before
*/
public function before()
{
if (!extension_loaded('sodium') && !defined('SODIUM_COMPAT_POLYFILLED_RISTRETTO255')) {
$this->markTestSkipped('ext/sodium is not installed; skipping the compatibility test suite.');
}
ParagonIE_Sodium_Compat::$disableFallbackForUnitTests = true;
}
public function testRistrettoFromHash()
{
$seed = random_bytes(64);
$fromhash_1 = ParagonIE_Sodium_Compat::ristretto255_from_hash($seed, true);
$fromhash_2 = sodium_crypto_core_ristretto255_from_hash($seed);
$this->assertSame(
sodium_bin2hex($fromhash_1),
sodium_bin2hex($fromhash_2)
);
}
public function testRistrettoOps()
{
$p = sodium_crypto_core_ristretto255_random();
$q = sodium_crypto_core_ristretto255_random();
// add
$r1 = sodium_crypto_core_ristretto255_add($p, $q);
$r2 = ParagonIE_Sodium_Compat::ristretto255_add($p, $q);
$this->assertSame(sodium_bin2hex($r1), sodium_bin2hex($r2), 'add');
// sub
$p1 = sodium_crypto_core_ristretto255_sub($r1, $q);
$p2 = ParagonIE_Sodium_Compat::ristretto255_sub($r2, $q);
$this->assertSame(sodium_bin2hex($p1), sodium_bin2hex($p2), 'sub');
}
/**
* @throws SodiumException
*/
public function testRistrettoScalarOps()
{
$p = sodium_crypto_core_ristretto255_scalar_random();
$q = sodium_crypto_core_ristretto255_scalar_random();
// add
$r1 = sodium_crypto_core_ristretto255_scalar_add($p, $q);
$r2 = ParagonIE_Sodium_Compat::ristretto255_scalar_add($p, $q);
$this->assertSame(sodium_bin2hex($r1), sodium_bin2hex($r2), 'scalar_add');
// sub
$p1 = sodium_crypto_core_ristretto255_scalar_sub($r1, $q);
$p2 = ParagonIE_Sodium_Compat::ristretto255_scalar_sub($r2, $q);
$this->assertSame(sodium_bin2hex($p1), sodium_bin2hex($p2), 'scalar_sub');
// mul
$z1 = sodium_crypto_core_ristretto255_scalar_mul($p, $q);
$z2 = ParagonIE_Sodium_Compat::ristretto255_scalar_mul($p, $q);
$this->assertSame(sodium_bin2hex($z1), sodium_bin2hex($z2), 'scalar_mul');
// complement
$comp1 = sodium_crypto_core_ristretto255_scalar_complement($p1);
$comp2 = ParagonIE_Sodium_Compat::ristretto255_scalar_complement($p2);
$this->assertSame(sodium_bin2hex($comp1), sodium_bin2hex($comp2), 'scalar_complement');
// invert
$inv1 = sodium_crypto_core_ristretto255_scalar_invert($p1);
$inv2 = ParagonIE_Sodium_Compat::ristretto255_scalar_invert($p2);
$this->assertSame(sodium_bin2hex($inv1), sodium_bin2hex($inv2), 'scalar_invert');
// negate
$neg1 = sodium_crypto_core_ristretto255_scalar_negate($p1);
$neg2 = ParagonIE_Sodium_Compat::ristretto255_scalar_negate($p2);
$this->assertSame(sodium_bin2hex($neg1), sodium_bin2hex($neg2), 'scalar_negate');
// negate
$bytes = random_bytes(ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES);
$red1 = sodium_crypto_core_ristretto255_scalar_reduce($bytes);
$red2 = ParagonIE_Sodium_Compat::ristretto255_scalar_reduce($bytes);
$this->assertSame(sodium_bin2hex($red1), sodium_bin2hex($red2), 'scalar_reduce');
}
/**
* This follows along the example given in the libsodium documentation:
* @link https://libsodium.gitbook.io/doc/advanced/point-arithmetic/ristretto
*
* The calculation MUST be the same in our implementation and in libsodium's.
*
* @throws SodiumException
*/
public function testExchange()
{
$x = random_bytes(ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_HASHBYTES);
$px1 = sodium_crypto_core_ristretto255_from_hash($x);
$px2 = ParagonIE_Sodium_Compat::ristretto255_from_hash($x);
$this->assertSame(sodium_bin2hex($px1), sodium_bin2hex($px2), 'from_hash');
// Test basepoints
$temp1 = sodium_crypto_scalarmult_ristretto255_base($px1);
$temp2 = ParagonIE_Sodium_Compat::scalarmult_ristretto255_base($px2);
$this->assertSame(sodium_bin2hex($temp1), sodium_bin2hex($temp2), 'scalarmult_base');
// Random Scalar
$r = sodium_crypto_core_ristretto255_scalar_random();
$gr1 = sodium_crypto_scalarmult_ristretto255_base($r);
$gr2 = ParagonIE_Sodium_Compat::scalarmult_ristretto255_base($r);
$this->assertSame(sodium_bin2hex($gr1), sodium_bin2hex($gr2), 'scalarmult_base');
$a1 = sodium_crypto_core_ristretto255_add($px1, $gr1);
$a2 = ParagonIE_Sodium_Compat::ristretto255_add($px2, $gr2);
$this->assertSame(sodium_bin2hex($a1), sodium_bin2hex($a2), 'add');
$k = random_bytes(ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES);
$v1 = sodium_crypto_scalarmult_ristretto255_base($k);
$v2 = ParagonIE_Sodium_Compat::scalarmult_ristretto255_base($k);
$this->assertSame(sodium_bin2hex($v1), sodium_bin2hex($v2), 'scalarmult_base');
$this->assertSame(sodium_bin2hex($a1), sodium_bin2hex($a2), 'consistency check');
$b1 = sodium_crypto_scalarmult_ristretto255($k, $a1);
$b2 = ParagonIE_Sodium_Compat::scalarmult_ristretto255($k, $a2);
$this->assertSame(sodium_bin2hex($b1), sodium_bin2hex($b2), 'scalarmult');
$ir1 = sodium_crypto_core_ristretto255_scalar_negate($r);
$ir2 = ParagonIE_Sodium_Compat::ristretto255_scalar_negate($r);
$this->assertSame(sodium_bin2hex($ir1), sodium_bin2hex($ir2), 'negate');
$vir1 = sodium_crypto_scalarmult_ristretto255($ir1, $v1);
$vir2 = ParagonIE_Sodium_Compat::scalarmult_ristretto255($ir1, $v1);
$this->assertSame(sodium_bin2hex($vir1), sodium_bin2hex($vir2), 'scalarmult inverse');
}
/**
* These test cases broken on PHP 8.1
*
* @return string[][]
*/
public function brokenPHP81TestProvider()
{
return array(
array(
'71a330faff41651c6dfa6e4548877d2dc2b0c26056c2e7e17bfb14cf94a4b47c',
'92d753c7b3fef8b8b553e672823db0a052d7598999a3baacd5909f0c0a6d491f',
'0c7507876a0215c3bf5407680a7c0bef7116c9bca25deca316322d1647dff75a'
),
array(
'a57445510d01b93e6ac9b4b0df02edf58dd577c527636a508ac52a015848051c',
'30417da32e12af747c79dd8dd239db80d6621da155abb9bcf270dfbf7f621d4f',
'06a686c7a7ec35374f37f8f537e7e099ce60aaca1c0c009085cc5a8f43850005'
)
);
}
/**
* @test
* @dataProvider brokenPHP81TestProvider
* @throws SodiumException
*/
public function testBrokenPHP81($k_hex, $a_hex, $expect)
{
$k = sodium_hex2bin($k_hex);
$a = sodium_hex2bin($a_hex);
$b1 = sodium_crypto_scalarmult_ristretto255($k, $a);
$b2 = ParagonIE_Sodium_Compat::scalarmult_ristretto255($k, $a);
$this->assertSame($expect, sodium_bin2hex($b2), 'expectation failed (sodium_compat)');
$this->assertSame($expect, sodium_bin2hex($b1), 'expectation failed (PHP 8.1)');
$this->assertSame(sodium_bin2hex($b1), sodium_bin2hex($b2), 'consistency failed');
}
}
|