public static doubleAndAdd ( $hex, Bitpay\PointInterface $point, Bitpay\Util\CurveParameterInterface $parameters = null ) | ||
$point | Bitpay\PointInterface | |
$parameters | Bitpay\Util\CurveParameterInterface |
/** * Generates an uncompressed and compressed EC public key. * * @param \Bitpay\PrivateKey $privateKey * @return \Bitpay\PublicKey * @throws \Exception */ public function generate(PrivateKey $privateKey = null) { if ($privateKey instanceof PrivateKey) { $this->setPrivateKey($privateKey); } if (!empty($this->hex)) { return $this; } if (is_null($this->privateKey)) { throw new \Exception('Please `setPrivateKey` before you generate a public key'); } if (!$this->privateKey->isGenerated()) { $this->privateKey->generate(); } if (!$this->privateKey->isValid()) { throw new \Exception('Private Key is invalid and cannot be used to generate a public key'); } $point = new Point('0x' . substr(Secp256k1::G, 2, 64), '0x' . substr(Secp256k1::G, 66, 64)); $R = Util::doubleAndAdd('0x' . $this->privateKey->getHex(), $point); $RxHex = Util::encodeHex($R->getX()); $RyHex = Util::encodeHex($R->getY()); $RxHex = str_pad($RxHex, 64, '0', STR_PAD_LEFT); $RyHex = str_pad($RyHex, 64, '0', STR_PAD_LEFT); $this->x = $RxHex; $this->y = $RyHex; $this->hex = sprintf('%s%s', $RxHex, $RyHex); $this->dec = Util::decodeHex($this->hex); return $this; }
/** * Creates an ECDSA signature of $data. * * @param string * @return string * @throws \Exception */ public function sign($data) { if (!ctype_xdigit($this->hex)) { throw new \Exception('The private key must be in hex format.'); } if (empty($data)) { throw new \Exception('You did not provide any data to sign.'); } $e = Util::decodeHex(hash('sha256', $data)); do { if (substr(strtolower($this->hex), 0, 2) != '0x') { $d = '0x' . $this->hex; } else { $d = $this->hex; } $k = SecureRandom::generateRandom(32); $k_hex = '0x' . strtolower(bin2hex($k)); $n_hex = '0x' . Secp256k1::N; $Gx = '0x' . substr(Secp256k1::G, 2, 64); $Gy = '0x' . substr(Secp256k1::G, 66, 64); $P = new Point($Gx, $Gy); // Calculate a new curve point from Q=k*G (x1,y1) $R = Util::doubleAndAdd($k_hex, $P); $Rx_hex = Util::encodeHex($R->getX()); $Rx_hex = str_pad($Rx_hex, 64, '0', STR_PAD_LEFT); // r = x1 mod n $r = Math::mod('0x' . $Rx_hex, $n_hex); // s = k^-1 * (e+d*r) mod n $edr = Math::add($e, Math::mul($d, $r)); $invk = Math::invertm($k_hex, $n_hex); $kedr = Math::mul($invk, $edr); $s = Math::mod($kedr, $n_hex); // The signature is the pair (r,s) $signature = array('r' => Util::encodeHex($r), 's' => Util::encodeHex($s)); $signature['r'] = str_pad($signature['r'], 64, '0', STR_PAD_LEFT); $signature['s'] = str_pad($signature['s'], 64, '0', STR_PAD_LEFT); } while (Math::cmp($r, '0') <= 0 || Math::cmp($s, '0') <= 0); $sig = array('sig_rs' => $signature, 'sig_hex' => self::serializeSig($signature['r'], $signature['s'])); return $sig['sig_hex']['seq']; }
public function testDoubleAndAdd() { $point = Util::doubleAndAdd('0', new Point(0, 0)); $this->assertInstanceOf('Bitpay\\PointInterface', $point); $this->assertTrue($point->isInfinity()); $point = Util::doubleAndAdd('1', new Point(1, 1)); $this->assertEquals('1', $point->getX()); $this->assertEquals('1', $point->getY()); $point = new Point('0x' . substr(Secp256k1::G, 2, 64), '0x' . substr(Secp256k1::G, 66, 64)); $R = Util::doubleAndAdd('0xb7dafe35d7d1aab78b53982c8ba554584518f86d50af565c98e053613c8f15e0', $point); $this->assertEquals('14976827122927988984909748681266837395089399768482149532452617485742004777865', $R->getX()); $this->assertEquals('5009713401941157350243425146365130573323232660945282226881202857781593637456', $R->getY()); $R = Util::doubleAndAdd('0xfd7c6914790d3bbf3184d9830e3f1a327e951e3478dd0b28f0fd3b0e774bbd68', $point); $this->assertEquals('65041784833307054098962518952641430476519680065454324565175938819000678523383', $R->getX()); $this->assertEquals('53140314933116045874248958072587249546886301333167874306830834776596206062743', $R->getY()); }