Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
k6xiao opened this issue Apr 2, 2022 · 5 comments

Comments

@k6xiao
Copy link

k6xiao commented Apr 2, 2022

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
Copy link
Author

k6xiao commented Apr 2, 2022

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

@grkamil
Copy link
Member

grkamil commented Apr 2, 2022

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
Copy link
Member

grkamil commented Apr 2, 2022

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

@k6xiao
Copy link
Author

k6xiao commented Apr 2, 2022

@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
Copy link
Author

k6xiao commented Apr 2, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants