public function atestDeterministicSign() { $f = file_get_contents(__DIR__ . '/../../data/rfc6979.json'); $json = json_decode($f); $math = $this->math; $G = $this->G; foreach ($json->test as $test) { $G = CurveFactory::getGeneratorByName($test->curve); // Initialize private key and message hash (decimal) $privateKey = new PrivateKey($math, $G, $math->hexDec($test->privKey)); $messageHash = $this->math->hexDec(hash($test->algorithm, $test->message)); // Derive K $drbg = RandomGeneratorFactory::getHmacRandomGenerator($privateKey, $messageHash, $test->algorithm); // K must be correct (from privatekey and message hash) $k = $drbg->generate($G->getOrder()); $this->assertEquals(strtolower($test->expectedK), $math->decHex($k)); $hashBits = $this->math->baseConvert($messageHash, 10, 2); $size = NumberSize::bnNumBits($this->math, $messageHash); $messageHash = $this->math->baseConvert(substr($hashBits, 0, $size), 2, 10); $signer = new Signer($math); $sig = $signer->sign($privateKey, $messageHash, $k); // R and S should be correct $sR = $this->math->hexDec($test->expectedR); $sS = $this->math->hexDec($test->expectedS); $this->assertTrue($signer->verify($privateKey->getPublicKey(), $sig, $messageHash)); $this->assertSame($sR, $sig->getR(), 'r'); $this->assertSame($sS, $sig->getS(), 's'); } }
/** * @param GeneratorPoint $G * @param $hash * @return int|string */ public function truncateHash(GeneratorPoint $G, $hash) { $hexSize = strlen($this->adapter->decHex($hash)); $hashBits = $this->adapter->baseConvert($hash, 10, 2); if (strlen($hashBits) < $hexSize * 4) { $hashBits = str_pad($hashBits, $hexSize * 4, '0', STR_PAD_LEFT); } $messageHash = $this->adapter->baseConvert(substr($hashBits, 0, NumberSize::bnNumBits($this->adapter, $G->getOrder())), 2, 10); return $messageHash; }
/** * @dataProvider getHmacTestSet * @param GeneratorPoint $G * @param integer $size * @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, $size, $privKey, $algo, $message, $eK, $eR, $eS) { //echo "Try {$test->curve} / {$test->algorithm} / '{$test->message}'\n"; $math = $G->getAdapter(); // Initialize private key and message hash (decimal) $privateKey = $G->getPrivateKeyFrom($math->hexDec($privKey)); $hashHex = hash($algo, $message); $messageHash = $math->hexDec($hashHex); // Derive K $drbg = RandomGeneratorFactory::getHmacRandomGenerator($privateKey, $messageHash, $algo); $k = $drbg->generate($G->getOrder()); $this->assertEquals($k, $math->hexdec($eK), 'k'); $hexSize = strlen($hashHex); $hashBits = $math->baseConvert($messageHash, 10, 2); if (strlen($hashBits) < $hexSize * 4) { $hashBits = str_pad($hashBits, $hexSize * 4, '0', STR_PAD_LEFT); } $messageHash = $math->baseConvert(substr($hashBits, 0, NumberSize::bnNumBits($math, $G->getOrder())), 2, 10); $signer = new Signer($math); $sig = $signer->sign($privateKey, $messageHash, $k); // Should be consistent $this->assertTrue($signer->verify($privateKey->getPublicKey(), $sig, $messageHash)); // R and S should be correct $sR = $math->hexDec($eR); $sS = $math->hexDec($eS); $this->assertSame($sR, $sig->getR(), "r {$sR} == " . $sig->getR()); $this->assertSame($sS, $sig->getS(), "s {$sR} == " . $sig->getS()); }
/** * @dataProvider getBnNumBytesNumbers */ public function testNumBytes(MathAdapterInterface $adapter, $number, $expected) { $size = NumberSize::bnNumBytes($adapter, $adapter->hexDec($number)); $this->assertEquals($expected, $size); }
/** * Generate a nonce based on the given $max * * {@inheritDoc} * @see \Mdanter\Ecc\Random\RandomNumberGeneratorInterface::generate() */ public function generate($max) { if (is_null($this->result)) { $v = NumberSize::getCeiledByteSize($this->math, $max); while (true) { $hex = bin2hex($this->bytes($v)); $rand = $this->math->hexDec($hex); // Check k is between [1, ... $max] if ($this->math->cmp(1, $rand) <= 0 && $this->math->cmp($rand, $max) < 0) { break; } // Otherwise derive another and try again. $this->update(chr(0)); } $this->result = $rand; } return $this->result; }
/** * @param int|string $integer * @param bool $fNegative * @return int|string */ public function parseCompact($integer, $fNegative) { if (!is_bool($fNegative)) { throw new \InvalidArgumentException('CompactInteger::read() - flag must be boolean!'); } $size = (int) NumberSize::bnNumBytes($this, $integer); if ($this->cmp($size, 3) <= 0) { $compact = $this->leftShift($this->getLow64($integer), $this->mul(8, $this->sub(3, $size))); } else { $compact = $this->rightShift($integer, $this->mul(8, $this->sub($size, 3))); $compact = $this->getLow64($compact); } if ($this->cmp($this->bitwiseAnd($compact, $this->hexDec('00800000')), 0) > 0) { $compact = $this->rightShift($compact, 8); $size++; } $compact = $this->bitwiseOr($compact, $this->leftShift($size, 24)); if ($fNegative && $this->cmp($this->bitwiseAnd($compact, $this->hexDec('007fffff')), 0) > 0) { /// ? $compact = $this->bitwiseOr($compact, $this->hexDec('00800000')); } return $compact; }
/** * @dataProvider getByte */ public function testGetFlooredByteSize(MathAdapterInterface $adapter, $x, $expected) { $size = NumberSize::getFlooredByteSize($adapter, $x); $this->assertEquals($expected, $size); }
/** * @param int|string $max * @return int|string */ public function generate($max) { $bytes = NumberSize::getFlooredByteSize($this->adapter, $max); $iv = mcrypt_create_iv($bytes, \MCRYPT_DEV_URANDOM); return $this->adapter->hexDec(bin2hex($iv)); }