public function _doCompressionConsistence(MathAdapterInterface $adapter, NumberTheory $theory) { foreach ($this->compression_data as $o) { // Try and regenerate the y coordinate from the parity byte // '04' . $x_coordinate . determined y coordinate should equal $o->decompressed // Tests squareRootModP which touches most functions in NumberTheory $y_byte = substr($o->compressed, 0, 2); $x_coordinate = substr($o->compressed, 2); $x = $adapter->hexDec($x_coordinate); // x^3 $x3 = $adapter->powmod($x, 3, $this->generator->getCurve()->getPrime()); // y^2 $y2 = $adapter->add($x3, $this->generator->getCurve()->getB()); // y0 = sqrt(y^2) $y0 = $theory->squareRootModP($y2, $this->generator->getCurve()->getPrime()); if ($y_byte == '02') { $y_coordinate = $adapter->mod($y0, 2) == '0' ? gmp_strval(gmp_init($y0, 10), 16) : gmp_strval(gmp_sub($this->generator->getCurve()->getPrime(), $y0), 16); } else { $y_coordinate = $adapter->mod($y0, 2) == '0' ? gmp_strval(gmp_sub($this->generator->getCurve()->getPrime(), $y0), 16) : gmp_strval(gmp_init($y0, 10), 16); } $y_coordinate = str_pad($y_coordinate, 64, '0', STR_PAD_LEFT); // Successfully regenerated uncompressed ECDSA key from the x coordinate and the parity byte. $this->assertTrue('04' . $x_coordinate . $y_coordinate == $o->decompressed); } }
/** * Initialize a new instance. * * @param MathAdapterInterface $adapter * @param GeneratorPoint $generator * @param PointInterface $point * @throws \LogicException * @throws \RuntimeException */ public function __construct(MathAdapterInterface $adapter, GeneratorPoint $generator, PointInterface $point) { $this->curve = $generator->getCurve(); $this->generator = $generator; $this->point = $point; $this->adapter = $adapter; $n = $generator->getOrder(); if ($n == null) { throw new \LogicException("Generator must have order."); } if (!$point->mul($n)->isInfinity()) { throw new \RuntimeException("Generator point order is bad."); } if ($adapter->cmp($point->getX(), 0) < 0 || $adapter->cmp($n, $point->getX()) <= 0 || $adapter->cmp($point->getY(), 0) < 0 || $adapter->cmp($n, $point->getY()) <= 0) { throw new \RuntimeException("Generator point has x and y out of range."); } }
/** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PrivateKeyInterface::getCurve() */ public function getCurve() { return $this->generator->getCurve(); }
/** * Take X, Y, and a generator point, and we can get what we need! * * @param Math $math * @param GeneratorPoint $generator * @param int|string $x * @param int|string $y */ public function __construct(Math $math, GeneratorPoint $generator, $x, $y) { parent::__construct($math, $generator->getCurve(), $x, $y, $generator->getOrder()); }
public function parseKey(GeneratorPoint $generator, $data) { $point = $this->pointSerializer->unserialize($generator->getCurve(), $data); return new PublicKey($this->adapter, $generator, $point); }
/** * based on php-bitcoin-signature-routines implementation (which is based on bitcoinjs-lib's implementation) * which is SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public Key Recovery Operation" * http://www.secg.org/sec1-v2.pdf * * @param $r * @param $s * @param $e * @param $recoveryFlags * @param GeneratorPoint $G * @return bool|PublicKey */ private static function recoverPubKey($r, $s, $e, $recoveryFlags, GeneratorPoint $G) { $math = EccFactory::getAdapter(); $isYEven = ($recoveryFlags & 1) != 0; $isSecondKey = ($recoveryFlags & 2) != 0; $curve = $G->getCurve(); $signature = new Signature($r, $s); // Precalculate (p + 1) / 4 where p is the field order $p_over_four = $math->div($math->add($curve->getPrime(), 1), 4); // 1.1 Compute x if (!$isSecondKey) { $x = $r; } else { $x = $math->add($r, $G->getOrder()); } // 1.3 Convert x to point $alpha = $math->mod($math->add($math->add($math->pow($x, 3), $math->mul($curve->getA(), $x)), $curve->getB()), $curve->getPrime()); $beta = $math->powmod($alpha, $p_over_four, $curve->getPrime()); // If beta is even, but y isn't or vice versa, then convert it, // otherwise we're done and y == beta. if (($math->mod($beta, 2) == 0) == $isYEven) { $y = $math->sub($curve->getPrime(), $beta); } else { $y = $beta; } // 1.4 Check that nR is at infinity (implicitly done in constructor) $R = $G->getCurve()->getPoint($x, $y); $point_negate = function (PointInterface $p) use($math, $G) { return $G->getCurve()->getPoint($p->getX(), $math->mul($p->getY(), -1)); }; // 1.6.1 Compute a candidate public key Q = r^-1 (sR - eG) $rInv = $math->inverseMod($r, $G->getOrder()); $eGNeg = $point_negate($G->mul($e)); $Q = $R->mul($s)->add($eGNeg)->mul($rInv); // 1.6.2 Test Q as a public key $signer = new Signer($math); $Qk = new PublicKey($math, $G, $Q); if ($signer->verify($Qk, $signature, $e)) { return $Qk; } return false; }