完整代码
<?php
class BitcoinECDSA {
public $k, $p, $G;
public function __construct() {
$this->p = gmp_init('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16);
$this->G = ['x' => gmp_init('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
'y' => gmp_init('32670510020758816978083085130507043184471273380659243275938904335757337482424')];
}
public function doublePoint($pt) {
$p = $this->p;
$slope = gmp_mod(gmp_mul(gmp_invert(gmp_mod(gmp_mul(gmp_init(2), $pt['y']), $p), $p), gmp_add(gmp_mul(gmp_init(3), gmp_pow($pt['x'], 2)), gmp_init(0))), $p);
return ['x' => gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt['x']), $pt['x']), $p),
'y' => gmp_mod(gmp_sub(gmp_mul($slope, gmp_sub($pt['x'], gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt['x']), $pt['x']), $p))), $pt['y']), $p)];
}
public function addPoints($pt1, $pt2) {
if (gmp_cmp($pt1['x'], $pt2['x']) === 0 && gmp_cmp($pt1['y'], $pt2['y']) === 0) return $this->doublePoint($pt1);
$slope = gmp_mod(gmp_mul(gmp_sub($pt1['y'], $pt2['y']), gmp_invert(gmp_sub($pt1['x'], $pt2['x']), $this->p)), $this->p);
return ['x' => gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt1['x']), $pt2['x']), $this->p),
'y' => gmp_mod(gmp_sub(gmp_mul($slope, gmp_sub($pt1['x'], gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt1['x']), $pt2['x']), $this->p))), $pt1['y']), $this->p)];
}
public function mulPoint($k, $pG) {
$k = gmp_init($k, 10);
$kBin = gmp_strval($k, 2);
$lastPoint = $pG;
for ($i = 1; $i < strlen($kBin); $i++) {
$lastPoint = $kBin[$i] === '1' ? $this->addPoints($this->doublePoint($lastPoint), $pG) : $this->doublePoint($lastPoint);
}
return $lastPoint;
}
public function getPubKeyPoints() {
if (!isset($this->k)) throw new \Exception('No Private Key defined');
$pubKey = $this->mulPoint($this->k, $this->G);
return ['x' => $pubKey['x'],
'y' => $pubKey['y']];
}
public function getPubKey(array $pubKeyPts = []) {
if (empty($pubKeyPts)) $pubKeyPts = $this->getPubKeyPoints();
return $pubKeyPts;
}
public function setPrivateKey($k) {
$this->k = $k;
}
}
// Ensure $p is a GMP number
$p = gmp_init('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16);
// Initialize the private key as a GMP object
echo $k = gmp_invert("2",$p);
// $k = "57896044618658097711785492504343953926634992332820282019728792003954417335832";
$bitcoinECDSA = new BitcoinECDSA();
$bitcoinECDSA->setPrivateKey($k);
$s = $bitcoinECDSA->getPubKey();
print_r($s);
?>
错误信息:
警告:gmp_init():无法将变量转换为 GMP - 类型错误
问题代码(代码底部):
// Initialize the private key as a GMP object
echo $k = gmp_invert("2",$p);
// $k = "57896044618658097711785492504343953926634992332820282019728792003954417335832";
这里,
gmp_invert("2",$p) = 57896044618658097711785492504343953926634992332820282019728792003954417335832
如果我取消评论
// $k = "57896044618658097711785492504343953926634992332820282019728792003954417335832";
效果很好。但它不适用于
gmp_invert("2",$p)
。 为什么?
出现此问题是因为 gmp_invert 返回 GMP 对象,而不是字符串。我不应该对 gmp_invert 的结果使用 gmp_init 。相反,我可以直接使用结果。这是更正后的代码:
<?php
class BitcoinECDSA {
public $k, $p, $G;
public function __construct() {
$this->p = gmp_init('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16);
$this->G = ['x' => gmp_init('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
'y' => gmp_init('32670510020758816978083085130507043184471273380659243275938904335757337482424')];
}
public function doublePoint($pt) {
$p = $this->p;
$slope = gmp_mod(gmp_mul(gmp_invert(gmp_mod(gmp_mul(gmp_init(2), $pt['y']), $p), $p), gmp_add(gmp_mul(gmp_init(3), gmp_pow($pt['x'], 2)), gmp_init(0))), $p);
return ['x' => gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt['x']), $pt['x']), $p),
'y' => gmp_mod(gmp_sub(gmp_mul($slope, gmp_sub($pt['x'], gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt['x']), $pt['x']), $p))), $pt['y']), $p)];
}
public function addPoints($pt1, $pt2) {
if (gmp_cmp($pt1['x'], $pt2['x']) === 0 && gmp_cmp($pt1['y'], $pt2['y']) === 0) return $this->doublePoint($pt1);
$slope = gmp_mod(gmp_mul(gmp_sub($pt1['y'], $pt2['y']), gmp_invert(gmp_sub($pt1['x'], $pt2['x']), $this->p)), $this->p);
return ['x' => gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt1['x']), $pt2['x']), $this->p),
'y' => gmp_mod(gmp_sub(gmp_mul($slope, gmp_sub($pt1['x'], gmp_mod(gmp_sub(gmp_sub(gmp_pow($slope, 2), $pt1['x']), $pt2['x']), $this->p))), $pt1['y']), $this->p)];
}
public function mulPoint($k, $pG) {
$k = $k; //gmp_init($k, 10);
$kBin = gmp_strval($k, 2);
$lastPoint = $pG;
for ($i = 1; $i < strlen($kBin); $i++) {
$lastPoint = $kBin[$i] === '1' ? $this->addPoints($this->doublePoint($lastPoint), $pG) : $this->doublePoint($lastPoint);
}
return $lastPoint;
}
public function getPubKeyPoints() {
if (!isset($this->k)) throw new \Exception('No Private Key defined');
$pubKey = $this->mulPoint($this->k, $this->G);
return ['x' => $pubKey['x'],
'y' => $pubKey['y']];
}
public function getPubKey(array $pubKeyPts = []) {
if (empty($pubKeyPts)) $pubKeyPts = $this->getPubKeyPoints();
return $pubKeyPts;
}
public function setPrivateKey($k) {
$this->k = $k;
}
}
// Ensure $p is a GMP number
$p = gmp_init('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16);
// Initialize the private key as a GMP object
$k = gmp_invert("2", $p);
//$k = "57896044618658097711785492504343953926634992332820282019728792003954417335832";
$bitcoinECDSA = new BitcoinECDSA();
$bitcoinECDSA->setPrivateKey($k);
$s = $bitcoinECDSA->getPubKey();
print_r($s);
?>