File "SpecBasedCurveTest.php"
Full Path: /home/digidjwy/public_html/wp-content/plugins/mycryptocheckout/vendor/mdanter/ecc/tests/unit/Crypto/SpecBasedCurveTest.php
File size: 16 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace Mdanter\Ecc\Tests\Curves;
use Mdanter\Ecc\Crypto\Signature\Signature;
use Mdanter\Ecc\Random\RandomGeneratorFactory;
use Mdanter\Ecc\Serializer\Point\CompressedPointSerializer;
use Mdanter\Ecc\Serializer\Point\UncompressedPointSerializer;
use Mdanter\Ecc\Tests\AbstractTestCase;
use Mdanter\Ecc\Primitives\GeneratorPoint;
use Symfony\Component\Yaml\Yaml;
use Mdanter\Ecc\Curves\CurveFactory;
use Mdanter\Ecc\Crypto\Signature\Signer;
class SpecBasedCurveTest extends AbstractTestCase
{
const CAUSE_MSG = "message"; // 1
const CAUSE_R = "r"; // 2
const CAUSE_S = "s"; // 3
const CAUSE_Q = "publicKey"; // 4
const DEFAULT_COVERAGE_SHARDS = 5;
/**
* @var array
*/
private $fileCache = [];
/**
* @return array
*/
public function getFiles()
{
return [
__DIR__ . '/../../specs/secp-112r1.yml',
__DIR__ . '/../../specs/secp-192k1.yml',
__DIR__ . '/../../specs/secp-256k1.yml',
__DIR__ . '/../../specs/secp-256r1.yml',
__DIR__ . '/../../specs/secp-384r1.yml',
__DIR__ . '/../../specs/nist-p192.yml',
__DIR__ . '/../../specs/nist-p224.yml',
__DIR__ . '/../../specs/nist-p256.yml',
__DIR__ . '/../../specs/nist-p384.yml',
__DIR__ . '/../../specs/nist-p521.yml'
];
}
/**
* @param Yaml $yaml
* @param $fileName
* @return mixed
*/
public function readFile(Yaml $yaml, $fileName)
{
if (!isset($this->fileCache[$fileName])) {
if (!file_exists($fileName)) {
throw new \PHPUnit_Runner_Exception("Test fixture file {$fileName} does not exist");
}
$this->fileCache[$fileName] = $yaml->parse(file_get_contents($fileName));
}
return $this->fileCache[$fileName];
}
/**
* @param string $fixtureName
* @return array
*/
public function readTestFixture($fixtureName)
{
static $useShard;
$yaml = new Yaml();
$files = $this->getFiles();
$shards = 1;
if (getenv('COVERAGE')) {
$shards = getenv('COVERAGE_SHARDS');
if (null === $shards || (int) $shards === 0) {
$shards = self::DEFAULT_COVERAGE_SHARDS;
}
if (null === $useShard) {
$useShard = mt_rand(0, $shards - 1);
fwrite(STDERR, <<<TEXT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOTICE:
Sharding enabled for coverage run - testing shard {$useShard} of {$shards}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TEXT
);
}
}
$results = [];
foreach ($files as $fileName) {
$data = $this->readFile($yaml, $fileName);
if (!array_key_exists($fixtureName, $data)) {
continue;
}
$filesWorth = [
'name' => $data['name'],
'fixtures' => []
];
foreach ($data[$fixtureName] as $i => $fixture) {
if ($i % $shards != 0) {
continue;
}
$filesWorth['fixtures'][] = $fixture;
}
$results[] = $filesWorth;
}
return $results;
}
/**
* @return array
*/
public function getKeypairsTestSet()
{
$files = $this->readTestFixture('keypairs');
$datasets = [];
foreach ($files as $file) {
$generator = CurveFactory::getGeneratorByName($file['name']);
foreach ($file['fixtures'] as $fixture) {
$datasets[] = [
$file['name'],
$generator,
$fixture['k'],
$fixture['x'],
$fixture['y']
];
}
}
return $datasets;
}
/**
* @dataProvider getKeypairsTestSet()
* @param GeneratorPoint $generator
* @param string $k
* @param string $expectedX
* @param string $expectedY
*/
public function testGetPublicKey($name, GeneratorPoint $generator, $k, $expectedX, $expectedY)
{
$adapter = $generator->getAdapter();
$privateKey = $generator->getPrivateKeyFrom(gmp_init($k, 10));
$publicKey = $privateKey->getPublicKey();
$this->assertEquals($adapter->hexDec($expectedX), $adapter->toString($publicKey->getPoint()->getX()), $name);
$this->assertEquals($adapter->hexDec($expectedY), $adapter->toString($publicKey->getPoint()->getY()), $name);
$serializer = new UncompressedPointSerializer($adapter);
$serialized = $serializer->serialize($publicKey->getPoint());
$parsed = $serializer->unserialize($generator->getCurve(), $serialized);
$this->assertTrue($parsed->equals($publicKey->getPoint()));
$compressingSerializer = new CompressedPointSerializer($adapter);
$serialized = $compressingSerializer->serialize($publicKey->getPoint());
$parsed = $compressingSerializer->unserialize($generator->getCurve(), $serialized);
$this->assertTrue($parsed->equals($publicKey->getPoint()));
}
/**
* @return array
*/
public function getPublicKeyVerifyTestSet()
{
$files = $this->readTestFixture('pubkey');
$datasets = [];
foreach ($files as $file) {
$generator = CurveFactory::getGeneratorByName($file['name']);
foreach ($file['fixtures'] as $fixture) {
$datasets[] = [
$file['name'],
$generator,
$fixture['x'],
$fixture['y'],
$fixture['result'],
];
}
}
return $datasets;
}
/**
* @dataProvider getPublicKeyVerifyTestSet
* @param string $name
* @param GeneratorPoint $generator
* @param string $xHex
* @param string $yHex
* @param bool $expectedResult
*/
public function testPublicKeyVerify($name, GeneratorPoint $generator, $xHex, $yHex, $expectedResult)
{
$curve = $generator->getCurve();
$x = gmp_init($xHex, 16);
$y = gmp_init($yHex, 16);
// The true test
try {
$generator->getPublicKeyFrom($x, $y);
$fCurveHasPoint = true;
} catch (\Exception $e) {
$fCurveHasPoint = false;
}
$this->assertEquals($expectedResult, $fCurveHasPoint);
if ($expectedResult) {
// CurveFp.contains ...
// can only check the point exists on the curve after
// the fields have been checked against the subgroup
// order. If our fixture is valid, this method MUST
// return true.
$fCurveContains = $curve->contains($x, $y);
// Curve.getPoint must also succeed if the fixture is
// valid when the order isn't provided.
try {
$curve->getPoint($x, $y);
$fCurveGetPoint = true;
} catch (\Exception $e) {
$fCurveGetPoint = false;
}
$this->assertEquals(true, $fCurveContains);
$this->assertEquals(true, $fCurveGetPoint);
}
}
/**
* @return array
*/
public function getDiffieHellmanTestSet()
{
$files = $this->readTestFixture('diffie');
$datasets = [];
foreach ($files as $file) {
$generator = CurveFactory::getGeneratorByName($file['name']);
foreach ($file['fixtures'] as $fixture) {
$datasets[] = [
$generator,
$fixture['alice'],
$fixture['bob'],
$fixture['shared']
];
}
}
return $datasets;
}
/**
* @dataProvider getDiffieHellmanTestSet()
* @param GeneratorPoint $generator
* @param string $alice
* @param string $bob
* @param string $expectedX
*/
public function testGetDiffieHellmanSharedSecret(GeneratorPoint $generator, $alice, $bob, $expectedX)
{
$adapter = $generator->getAdapter();
$alicePrivKey = $generator->getPrivateKeyFrom(gmp_init($alice, 10));
$bobPrivKey = $generator->getPrivateKeyFrom(gmp_init($bob, 10));
$aliceDh = $alicePrivKey->createExchange($bobPrivKey->getPublicKey());
$bobDh = $bobPrivKey->createExchange($alicePrivKey->getPublicKey());
$this->assertEquals($adapter->hexDec($expectedX), $adapter->toString($aliceDh->calculateSharedKey()));
$this->assertEquals($adapter->hexDec($expectedX), $adapter->toString($bobDh->calculateSharedKey()));
}
/**
* @return array
*/
public function getHmacTestSet()
{
$files = $this->readTestFixture('hmac');
$datasets = [];
foreach ($files as $file) {
$generator = CurveFactory::getGeneratorByName($file['name']);
foreach ($file['fixtures'] as $fixture) {
$datasets[] = [
$generator,
$fixture['key'],
$fixture['algo'],
$fixture['message'],
strtolower($fixture['k']),
strtolower($fixture['r']),
strtolower($fixture['s'])
];
}
}
return $datasets;
}
/**
* @dataProvider getHmacTestSet
* @param GeneratorPoint $G
* @param string $privKey
* @param string $algo
* @param string $message
* @param string $eK expected K hex
* @param string $eR expected R hex
* @param string $eS expected S hex
*/
public function testHmacSignatures(GeneratorPoint $G, $privKey, $algo, $message, $eK, $eR, $eS)
{
$math = $G->getAdapter();
$privateKey = $G->getPrivateKeyFrom(gmp_init($privKey, 16));
$signer = new Signer($math);
$hashDec = $signer->hashData($G, $algo, $message);
$hmac = RandomGeneratorFactory::getHmacRandomGenerator($privateKey, $hashDec, $algo);
$k = $hmac->generate($G->getOrder());
$this->assertEquals($math->hexDec($eK), gmp_strval($k, 10), 'k');
$sig = $signer->sign($privateKey, $hashDec, $k);
// Should verify
$this->assertTrue($signer->verify($privateKey->getPublicKey(), $sig, $hashDec));
// R and S should be correct
$sR = $math->hexDec($eR);
$sS = $math->hexDec($eS);
$this->assertSame($sR, $math->toString($sig->getR()));
$this->assertSame($sS, $math->toString($sig->getS()));
}
/**
* @return array
*/
public function getEcdsaSignFixtures()
{
$files = $this->readTestFixture('ecdsa');
$datasets = [];
foreach ($files as $file) {
$generator = CurveFactory::getGeneratorByName($file['name']);
foreach ($file['fixtures'] as $testKeyPair) {
$algo = null;
$msg = null; // full message, not the digest
$hashRaw = null;
if (!array_key_exists('msg', $testKeyPair)) {
if (!array_key_exists('msg_full', $testKeyPair)) {
throw new \RuntimeException("Need full message if not given raw hash value");
}
if (!array_key_exists('algo', $testKeyPair)) {
throw new \RuntimeException("Need algorithm in order to hash message");
}
$algo = $testKeyPair['algo'];
$msg = $testKeyPair['msg_full'];
} else {
$hashRaw = $testKeyPair['msg'];
}
$datasets[] = [
$generator,
$testKeyPair['private'],
(string) $testKeyPair['k'],
(string) $testKeyPair['r'],
(string) $testKeyPair['s'],
$hashRaw,
$msg,
$algo,
];
}
}
return $datasets;
}
/**
* @dataProvider getEcdsaSignFixtures
* @param GeneratorPoint $G
* @param $privKeyHex
* @param $hashHex
* @param $kHex
* @param $eR
* @param $eS
* @param string|null $algo
*/
public function testEcdsaSignatureGeneration(GeneratorPoint $G, $privKeyHex, $kHex, $eR, $eS, $hashHex = null, $msg = null, $algo = null)
{
$math = $G->getAdapter();
$signer = new Signer($math);
$privateKey = $G->getPrivateKeyFrom(gmp_init($privKeyHex, 10));
if ($hashHex != null) {
$hash = gmp_init($hashHex, 16);
} else {
$hash = $signer->hashData($G, $algo, hex2bin($msg));
}
$k = gmp_init($kHex, 16);
$sig = $signer->sign($privateKey, $hash, $k);
// R and S should be correct
$sR = $math->hexDec($eR);
$sS = $math->hexDec($eS);
$this->assertSame($sR, $math->toString($sig->getR()));
$this->assertSame($sS, $math->toString($sig->getS()));
// Should verify
$this->assertTrue($signer->verify($privateKey->getPublicKey(), $sig, $hash));
}
/**
* @return array
*/
public function getEcdsaVerifyFixtures()
{
$files = $this->readTestFixture('ecdsa-verify');
$datasets = [];
foreach ($files as $file) {
$generator = CurveFactory::getGeneratorByName($file['name']);
foreach ($file['fixtures'] as $testKeyPair) {
$algo = null;
$msg = null; // full message, not the digest
$hashRaw = null;
$cause = null;
if (!array_key_exists('msg', $testKeyPair)) {
if (!array_key_exists('msg_full', $testKeyPair)) {
throw new \RuntimeException("Need full message if not given raw hash value");
}
if (!array_key_exists('algo', $testKeyPair)) {
throw new \RuntimeException("Need algorithm in order to hash message");
}
$algo = $testKeyPair['algo'];
$msg = $testKeyPair['msg_full'];
} else {
$hashRaw = $testKeyPair['msg'];
}
if (!$testKeyPair['result'] && array_key_exists("cause", $testKeyPair)) {
$cause = $testKeyPair["cause"];
}
$datasets[] = [
$generator,
(string) $testKeyPair['r'],
(string) $testKeyPair['s'],
(string) $testKeyPair['x'],
(string) $testKeyPair['y'],
$testKeyPair['result'],
$cause,
$hashRaw,
$msg,
$algo,
];
}
}
return $datasets;
}
/**
* @dataProvider getEcdsaVerifyFixtures
* @param GeneratorPoint $G
* @param $hashHex
* @param $eR
* @param $eS
* @param $x
* @param $y
* @param bool $result
* @param string $cause
* @param string|null $algo
*/
public function testEcdsaSignatureVerification(GeneratorPoint $G, $eR, $eS, $x, $y, $result, $cause = null, $hashHex = null, $msg = null, $algo = null)
{
$math = $G->getAdapter();
$signer = new Signer($math);
try {
$publicKey = $G->getPublicKeyFrom(gmp_init($x, 16), gmp_init($y, 16));
} catch (\Exception $e) {
throw new \RuntimeException("Unexpected exception parsing public key");
}
if ($hashHex != null) {
$hash = gmp_init($hashHex, 16);
} else {
$hash = $signer->hashData($G, $algo, hex2bin($msg));
}
$sig = new Signature(gmp_init($eR, 16), gmp_init($eS, 16));
// Should verify
$verify = $signer->verify($publicKey, $sig, $hash);
$this->assertEquals($result, $verify);
}
}