minter-php-bip-44
minter-php-bip-44 copied to clipboard
mnemonic to address,Unable to get: uncompressed public key / address / Y coordinate
php:
I have calculated the private key / compressed public key from 12 mnemonics
How to continue to get the address?
<?php
use BIP\BIP44; //助记词生成种子,种子生成私钥公钥
var_dump(mnemonic_to('chicken home nothing witness quick credit post crystal omit once arrow digital'));
// 助记词→私钥..
// mnemonic:助记词字符串 空格隔开
// passphrase:BIP39 密码(可选)
// address_index:地址索引
function mnemonic_to($mnemonic, $passphrase = '', $address_index = '0') {
$seed = hash_pbkdf2("sha512", $mnemonic, 'mnemonic' . $passphrase, 2048, 0, false);
$DerivationPath = "m/44'/60'/0'/0"; //ETH
$HDKey = BIP44::fromMasterSeed($seed)->derive($DerivationPath . "/" . $address_index);
dump($HDKey);
$HDKey2 = BIP44::fromMasterSeed($seed)->derive($DerivationPath);
dump($HDKey2);
return [
'privateKey' => $HDKey->privateKey, //私钥-64字符-bip44第0个 BIP-32 主密钥?
'publicKeyFull' => '???', //未压缩公钥-130字符-前缀04+椭圆x坐标(64字符)+椭圆y坐标(64字符)
'publicKey' => $HDKey->publicKey, //压缩公钥-66字符-前缀03+x(如果y是奇数),前缀02+x(如果y是偶数)
'address' => phpKeccak256($HDKey->publicKey), //地址-42字符
'mnemonic' => $mnemonic, //助记词-12个单词
'wordsCount' => count(explode(" ", $mnemonic)), //助记词数
'entropy' => BIP39::Words($mnemonic)->entropy, //熵
'seed' => $seed, // BIP39 种子
'derivationPath' => $DerivationPath, // BIP32 推导路径
'privateExtendedKey' => $HDKey2->getPrivateExtendedKey(), //BIP32 扩展私钥
'publicExtendedKey' => $HDKey2->getPublicExtendedKey(), //BIP32 扩展公钥
// 压缩公钥与未压缩公钥见 https://www.freesion.com/article/93101100036/
];
}
Compress public key to export uncompressed public key, find a python code:
def pow_mod(x, y, z):
"Calculate (x ** y) % z efficiently"
number = 1
while y:
if y & 1:
number = number * x % z
y >>= 1
x = x * x % z
return number
def get_uncompressed_key(compressed_key):
Pcurve = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 -1
y_parity = int(compressed_key[:2]) - 2
x = int(compressed_key[2:], 16)
a = (pow_mod(x, 3, Pcurve) + 7) % Pcurve
y = pow_mod(a, (Pcurve+1)//4, Pcurve)
if y % 2 != y_parity:
y = -y % Pcurve
uncompressed_key = '04{:x}{:x}'.format(x, y)
print(uncompressed_key)
get_uncompressed_key("03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69")
I tried to convert it to PHP, but it didn't work?
// 压缩公钥→未压缩公钥??
function get_publicKeyFull($publicKey) {
$Pcurve = pow(2, 256) - pow(2, 32) - pow(2, 9) - pow(2, 8) - pow(2, 7) - pow(2, 6) - pow(2, 4) - 1;
// 115792089237316195423570985008687907853269984665640564039457584007908834671663L
// dump(sprintf("%.0f", $Pcurve));die();
$Pcurve='115792089237316195423570985008687907853269984665640564039457584007913129639936';
$y_parity = substr($publicKey, 0, 2) - 2;
// 0
// dump($y_parity);die();
$x = hexdec(substr($publicKey, 2));
// 71839052358363470631853751699803328797577757426403183557600444745608567728750L
// dump(sprintf("%.0f", $x));die();
$x = '71839052358363476955434617780976633976216662647855454048510305751938619146240';
$a = (pow_mod($x, 3, $Pcurve) + 7) % $Pcurve;
// 72873585424191000744921829648974349838695761730891889171179429931878698071771L
// dump(sprintf("%.0f", $a));die();
$y = pow_mod($a, floor(($Pcurve + 1) / 4), $Pcurve);
// 109597386990766914382310286506229024192752021841214703090184145192016896144236L
// dump(sprintf("%.0f", $y));die();
if ($y % 2 != $y_parity) {
$y = -$y % $Pcurve;
}
$publicKeyFull = '04{:$x}{:$x}' . format($x, $y);
// 049ed37674ac068c10986f3bb957e4455987627462b3a14a2e6516a40bd1982a6ef24dec3b4114b4b5391a2353d44af3962bd2063e0157e3392950dce4a271336c
dump($publicKeyFull);
}
// 压缩公钥→未压缩公钥 辅助
function pow_mod($x, $y, $z) {
// "Calculate ($x ** $y) % $z efficiently"
return pow($x,$y)%$z;
$number = 1;
while ($y) {
if ($y & 1) {
$number = $number * $x % $z;
}
$y >>= 1;
$x = $x * $x % $z;
}
return $number;
}
// get_publicKeyFull("029ed37674ac068c10986f3bb957e4455987627462b3a14a2e6516a40bd1982a6e");
Something like that:
use kornrunner\Keccak;
use Minter\Library\ECDSA;
$publicKey = ECDSA::privateToPublic($privateKey); // $privateKey is privateKey in your returning array of function mnemonic_to()
$hash = Keccak::hash(hex2bin($publicKey), 256);
$ethAddress = '0x' . substr($hash, -40);
ECDSA::privateToPublic is:
public static function privateToPublic(string $privateKey): string
{
// create elliptic curve and get public key
$ellipticCurve = new EC('secp256k1');
$keyPair = new KeyPair($ellipticCurve, [
'priv' => $privateKey,
'privEnc' => 'hex'
]);
$publicKey = $keyPair->getPublic('hex');
return substr($publicKey, 2, 130);
}
from our sdk
@grkamil 你的方法可以 我引用我本地现有的成功:
<?
require_once './vendor/autoload.php';
use kornrunner\Keccak;
use Elliptic\EC\KeyPair;
use Elliptic\EC;
function privateToPublic(string $privateKey): string
{
$ellipticCurve = new EC('secp256k1');
$keyPair = new KeyPair($ellipticCurve, [
'priv' => $privateKey,
'privEnc' => 'hex'
]);
$publicKey = $keyPair->getPublic('hex');
return substr($publicKey, 2, 130);
}
$privateKey='3454c523a62768d99649c90f1b0ce2db956db1f54707cdac705395b169037ea4';
$publicKey = privateToPublic($privateKey); // $privateKey is privateKey in your returning array of function mnemonic_to()
$hash = Keccak::hash(hex2bin($publicKey), 256);
$ethAddress = '0x' . substr($hash, -40);
echo $ethAddress; // 0x50332c5578de9648c3ab4a485329eb570f14a38d
我这里修改了 minter-php-bip-44 里的 HDkey.php 文件:
protected $data = [
'version' => null,
'depth' => 0,
'index' => '00000000',
'privateKey' => null,
'publicKey' => null,
'publicKeyFull' => null,
'chainCode' => null,
'fingerprint' => '00000000',
'parentFingerprint' => '00000000'
];
//.....这里代码没动
protected $ellipticCurve;
protected $KeyPair;
//.....这里代码没动
public function generateKeysFromPrivate(string $privateKey): void
{
if(empty($privateKey)) {
throw new \Exception('Invalid private key');
}
$this->ellipticCurve = new EC('secp256k1');
$this->$keyPair = new KeyPair($this->ellipticCurve, [
'priv' => $privateKey,
'privEnc' => 'hex'
]);
$this->data['privateKey'] = str_repeat('0', 64 - strlen($privateKey)) . $privateKey;
$this->data['publicKey'] = $this->$keyPair->getPublic(true, 'hex');
$this->data['publicKeyFull'] = $this->$keyPair->getPublic(false, 'hex');
$this->data['address'] = $this->publicKeyFullToAddress($this->data['publicKeyFull']);
$this->data['fingerprint'] = $this->computeFingerprint($this->data['publicKey']);
}
/**
* Compute address from publicKeyFull
*
* @param string $privateKey
* @return string
*/
protected function publicKeyFullToAddress(string $publicKeyFull): string
{
return "0x" . substr(Keccak::hash(substr(hex2bin($publicKeyFull), 1), 256), 24);
}