minter-php-bip-44 icon indicating copy to clipboard operation
minter-php-bip-44 copied to clipboard

mnemonic to address,Unable to get: uncompressed public key / address / Y coordinate

Open k6xiao opened this issue 3 years ago • 5 comments

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/
    ];
}

k6xiao avatar Apr 02 '22 07:04 k6xiao

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");

k6xiao avatar Apr 02 '22 08:04 k6xiao

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);

grkamil avatar Apr 02 '22 08:04 grkamil

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 avatar Apr 02 '22 08:04 grkamil

@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

k6xiao avatar Apr 02 '22 11:04 k6xiao

我这里修改了 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);
    }

k6xiao avatar Apr 02 '22 11:04 k6xiao