x)) { return ''; } if (gmp_strval(gmp_mod('0x'.$this->y, '0x02')) == '1') { return sprintf('03%s', $this->x); } else { return sprintf('02%s', $this->x); } } /** * @param PrivateKey */ public static function createFromPrivateKey(PrivateKey $private) { $public = new self(); $public->setPrivateKey($private); return $public; } /** * @return KeyInterface */ public function setPrivateKey(PrivateKey $privateKey) { $this->privateKey = $privateKey; return $this; } /** * Generates an uncompressed and compressed EC public key. * * @param \Bitpay\PrivateKey $privateKey * * @return Bitpay\PublicKey */ public function generate() { 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, 0, 62), '0x'.substr(Secp256k1::G, 62, 62) ); $R = Gmp::doubleAndAdd( '0x'.$this->privateKey->getHex(), $point ); $RxHex = Util::encodeHex($R->getX()); $RyHex = Util::encodeHex($R->getY()); while (strlen($RxHex) < 64) { $RxHex .= 0; } while (strlen($RyHex) < 64) { $RyHex .= 0; } $this->x = $RxHex; $this->y = $RyHex; $this->hex = sprintf('04%s%s', $RxHex, $RyHex); $this->dec = Util::decodeHex(sprintf('04%s%s', $R->getX(), $R->getY())); return $this; } /** * Checks to see if the public key is not blank and contains * valid decimal and hex valules for this->hex & this->dec * * @return boolean */ public function isValid() { return ((!empty($this->hex) && !ctype_xdigit($this->hex)) && (!empty($this->dec) && !ctype_digit($this->dec))); } /** * @return SinKey */ public function getSin() { if (null === $this->sin) { $this->sin = new SinKey(); $this->sin->setPublicKey($this); $this->sin->generate(); } return $this->sin; } }