php中从公钥到比特币地址的散列

php中从公钥到比特币地址的散列,php,hash,public-key-encryption,bitcoin,Php,Hash,Public Key Encryption,Bitcoin,我试图按照使用php将65字节公钥转换为比特币地址所需的说明进行操作。说明很明确。有谁能帮助我在php中实现这一点的实用性吗 说明是 1-取其生成的相应公钥(65字节,1字节0x04,32字节对应X坐标,32字节对应Y坐标) 0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6 2-对公钥执

我试图按照使用php将65字节公钥转换为比特币地址所需的说明进行操作。说明很明确。有谁能帮助我在php中实现这一点的实用性吗

说明是

1-取其生成的相应公钥(65字节,1字节0x04,32字节对应X坐标,32字节对应Y坐标)

0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6

2-对公钥执行SHA-256哈希

600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408

3-对SHA-256的结果执行RIPEMD-160哈希运算

010966776006953D5567439E5E39F86A0D273BEE

4-在RIPEMD-160哈希前面添加版本字节(主网络为0x00)

00010966776006953D5567439E5E39F86A0D273BEE

5-对扩展的RIPEMD-160结果执行SHA-256哈希

445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094

6-对上一个SHA-256哈希的结果执行SHA-256哈希

D61967F63C7DD183914A4AE452C9F6AD5D462CE3D277798075B107615C1A8A30

7-获取第二个SHA-256哈希的前4个字节。这是地址校验和

D61967F6

8-将第7点的4个校验和字节添加到第4点的扩展RIPEMD-160散列的末尾。这是25字节二进制比特币地址

00010966776006953D5567439E5E39F86A0D273BEED61967F6

9-使用Base58Check编码将字节字符串的结果转换为base58字符串。这是最常用的比特币地址格式

16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM

我的第一次尝试是

// step 1

$publickey='0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6';
$step1=$publickey;

echo "step1 ".$publickey."<br>";

// step 2

$step2=hash("sha256",$step1);
echo "step2 ".$step2."<br>";

// step 3

$step3=hash('ripemd160',$step2);
echo "step3 ".$step3."<br>";

// step 4

$step4="00".$step3;
echo "step4 ".$step4."<br>";

// step 5

$step5=hash("sha256",$step4);
echo "step5 ".$step5."<br>";

// step 6

$step6=hash("sha256",$step5);
echo "step6 ".$step6."<br>";

// step 7

$checksum=substr($step6,0,8);
echo "step7 ".$checksum."<br>";

// step 8

$step8=$step4.$checksum;
echo "step8 ".$step8."<br>";

//step 9

$step9=base58_encode($step8);
echo "step9 ".$step9."<br><br>";
Base58函数是

function base58_encode($input)
{
    $alphabet =     '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
    $base_count = strval(strlen($alphabet));
    $encoded = '';
    while (floatval($input) >= floatval($base_count))
    {
        $div = bcdiv($input, $base_count);
        $mod = bcmod($input, $base_count);
        $encoded = substr($alphabet, intval($mod), 1) . $encoded;
        $input = $div;
    }
    if (floatval($input) > 0)
    {
        $encoded = substr($alphabet, intval($input), 1) . $encoded;
    }
    return($encoded);
}

仔细查看变量名$publickey与$publickey-票据资本化不同。

您的问题如下:

  • 变量名$publickey和$publickey不相等
  • $checksum=substr($step6,0,4)应该是
    $checksum=substr($step6,0,8)
    
  • $step8=$step4+$checksum应该是
    $step8=$step4.$checksum
  • 另外,我不知道你的
    base58_encode()
    函数来自哪里,但我希望它使用BCmath,因为
    00ba084d3f143f28996809d3f1d7dffed472b39d8de7a39cf51
    [步骤8的结果]表示的数字太大,PHP无法在内部处理

    编辑 我今天的工作非常无聊,这是我的转换代码,带奖金BCmath,用于ginormous[比如说,58位?]数字

    <?php
    
    // original arbitrary encode function
    function arb_encode($num, $basestr) {
        $base = strlen($basestr);
        $rep = '';
    
        while($num > 0) {
            $rem = $num % $base;
            $rep = $basestr[$rem] . $rep;
            $num = ($num - $rem) / $base;
        }
        return $rep;
    }
    
    function arb_decode($num, $basestr) {
        $base = strlen($basestr);
        $dec = 0;
    
        $num_arr = str_split((string)$num);
        $cnt = strlen($num);
        for($i=0; $i < $cnt; $i++) {
            $pos = strpos($basestr, $num_arr[$i]);
            if( $pos === false ) {
                Throw new Exception(sprintf('Unknown character %s at offset %d', $num_arr[$i], $i));
            }
            $dec = ($dec * $base) + $pos;
        }
        return $dec;
    }
    
    // BCmath version for huge numbers
    function bc_arb_encode($num, $basestr) {
        if( ! function_exists('bcadd') ) {
            Throw new Exception('You need the BCmath extension.');
        }
    
        $base = strlen($basestr);
        $rep = '';
    
        while( true ){
            if( strlen($num) < 2 ) {
                if( intval($num) <= 0 ) { break; }
            }
            $rem = bcmod($num, $base);
            $rep = $basestr[intval($rem)] . $rep;
            $num = bcdiv(bcsub($num, $rem), $base);
        }
        return $rep;
    }
    
    function bc_arb_decode($num, $basestr) {
        if( ! function_exists('bcadd') ) {
            Throw new Exception('You need the BCmath extension.');
        }
    
        $base = strlen($basestr);
        $dec = '0';
    
        $num_arr = str_split((string)$num);
        $cnt = strlen($num);
        for($i=0; $i < $cnt; $i++) {
            $pos = strpos($basestr, $num_arr[$i]);
            if( $pos === false ) {
                Throw new Exception(sprintf('Unknown character %s at offset %d', $num_arr[$i], $i));
            }
            $dec = bcadd(bcmul($dec, $base), $pos);
        }
        return $dec;
    }
    
    
    // base 58 alias
    function bc_base58_encode($num) {
        return bc_arb_encode($num, '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ');
    }
    function bc_base58_decode($num) {
        return bc_arb_decode($num, '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ');
    }
    
    //hexdec with BCmath
    function bc_hexdec($num) {
        return bc_arb_decode(strtolower($num), '0123456789abcdef');
    }
    function bc_dechex($num) {
        return bc_arb_encode($num, '0123456789abcdef');
    }
    
    // example
    $orig    = '00ba084d3f143f2896809d3f1d7dffed472b39d8de7a39cf51';
    $bten    = bc_hexdec($orig);
    $base58  = bc_base58_encode($bten);
    $backten = bc_base58_decode($base58);
    $back    = bc_dechex($backten);
    echo "Orig: " . $orig . "\n";
    echo "bten: " . $bten . "\n";
    echo "58:   " . $base58 . "\n";
    echo "ag10: " . $backten . "\n";
    echo "Back:   " . $back  . "\n";
    

    您可以看到,PHP已经过时了。[1.9E42 aka 1.9 quintillion septillion]我已经更新了我的代码,添加了
    arb_decode()
    函数,这些函数似乎可以正确执行操作。

    下面的解决方案要感谢Sammitch发现语法并提供基本转换

    <?php
    
    // step 1
    
    $publickey='0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6';
    
    $step1=hexStringToByteString($publickey);
    
    echo "step1 ".$publickey."<br>";
    
    // step 2
    
    $step2=hash("sha256",$step1);
    echo "step2 ".$step2."<br>";
    
    // step 3
    
    $step3=hash('ripemd160',hexStringToByteString($step2));
    echo "step3 ".$step3."<br>";
    
    // step 4
    
    $step4="00".$step3;
    echo "step4 ".$step4."<br>";
    
    // step 5
    
    $step5=hash("sha256",hexStringToByteString($step4));
    echo "step5 ".$step5."<br>";
    
    // step 6
    
    $step6=hash("sha256",hexStringToByteString($step5));
    echo "step6 ".$step6."<br>";
    
    // step 7
    
    $checksum=substr($step6,0,8);
    echo "step7 ".$checksum."<br>";
    
    // step 8
    
    $step8=$step4.$checksum;
    echo "step8 ".$step8."<br>";
    
    // step 9
    // base conversion is from hex to base58 via decimal. 
    // Leading hex zero converts to 1 in base58 but it is dropped
    // in the intermediate decimal stage.  Simply added back manually.
    
    $step9="1".bc_base58_encode(bc_hexdec($step8));
    echo "step9 ".$step9."<br><br>";
    
    ?>
    

    非常重要

    替换此项:'123456789abcdefghijkmnopqrstuvxyzabcdefghjklmnpqrstuvxyz'

    用这个:'123456789abcdefghjklmnpqrstuvxyzabcdefghijkmnopqrstuvxyz'

    在这里使用错误的代码将导致比特币交易失败或更糟,导致硬币消失在一个永远无法取回的幻影钱包中

    我不是开发人员,但我确认了更正。Base58符号图表在这里

    我在这里检查了我的工作

    输入密码短语:“测试地址”,不带引号

    然后,公钥是:047969A753F71135D4C792F384E546CD508514024B4EE40D12A014019B77D1B292763DFB8A108CF7A7119F80CA4A06E81B92464F5D8A754452CD2E641023A96D7

    您的地址结果:1GBG1MBVTYNTGGZHGGJ21A6MNJBNTQPCRS

    我的结果:1GCH1MBVUZOTGHZHGG21B6MNKBOURPDSS

    brainwallet.org结果:1GCH1MBVUZOTGHZHGG21B6MNKBOURPDSS


    我希望这样做可以避免出现耗时或代价高昂的错误。

    如果失败,则会显示一条错误消息。这是什么消息?@Mike W-添加输出-失败的原因是它不是预期的结果变量名
    $publickey
    $publickey
    不相等。@Sammitch-是-即使这样也不起作用!另外:
    $step8=$step4+$checksum应该是
    $step8=$step4.$checksum如果我正确解释了说明。谢谢(必须买一些新眼镜!)。固定和新的输出张贴。仍然不是预期的。@anthonyc查看我的编辑。我想你使用的是我找到的base58函数。[这是垃圾]我自己写的,也没那么垃圾,但它仍然无法处理这个数字有多大,4.5615018786978E+57。这是一个58位数字。我在上面加上了base58代码。在这个论坛的某个地方找到。我会试试你的,但我想知道为什么我第一个散列不正确?我应该把十六进制字符串转换成65字节的数组字符数组吗?@anthonyc,我不能这么说。我不知道散列函数应该对字母数字十六进制字符串还是二进制十六进制字符串进行操作。然而,我注意到,对于这么大的数字,
    base\u convert()
    也被破坏,请参见我的编辑。非常整洁!事实证明,我确实需要将十六进制字符串转换为字节字符串进行散列。此外,比特币使用一个特殊的base58,大写字母在小写字母之前。最后,00十六进制映射到1 base58,但通过十进制将其删除在步骤4中添加的前导零-因此我只在步骤9中将其添加回。完整的解决方案如下。许多人感谢答案已经有了这个替代,并且是正确的。还请注意,答案明确指出,您必须将base58修改为比特币base58。为了清楚起见,您可能需要修改您的“这是错误的”评论。anthonyc,非常感谢您在此处输入的代码。我在网上搜索这个解释。这对我理解这些概念有很大帮助!但这仍然是错误的。M
    Hex:           00ba084d3f143f2896809d3f1d7dffed472b39d8de7a39cf51
    PHP's decode:  4561501878697786606686086062428080084446806606846864824262
    Mine:          4561501878697784703577561586669353227270827349968709865297
    Wolfram Alpha: 4561501878697784703577561586669353227270827349968709865297
    
    <?php
    
    // step 1
    
    $publickey='0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6';
    
    $step1=hexStringToByteString($publickey);
    
    echo "step1 ".$publickey."<br>";
    
    // step 2
    
    $step2=hash("sha256",$step1);
    echo "step2 ".$step2."<br>";
    
    // step 3
    
    $step3=hash('ripemd160',hexStringToByteString($step2));
    echo "step3 ".$step3."<br>";
    
    // step 4
    
    $step4="00".$step3;
    echo "step4 ".$step4."<br>";
    
    // step 5
    
    $step5=hash("sha256",hexStringToByteString($step4));
    echo "step5 ".$step5."<br>";
    
    // step 6
    
    $step6=hash("sha256",hexStringToByteString($step5));
    echo "step6 ".$step6."<br>";
    
    // step 7
    
    $checksum=substr($step6,0,8);
    echo "step7 ".$checksum."<br>";
    
    // step 8
    
    $step8=$step4.$checksum;
    echo "step8 ".$step8."<br>";
    
    // step 9
    // base conversion is from hex to base58 via decimal. 
    // Leading hex zero converts to 1 in base58 but it is dropped
    // in the intermediate decimal stage.  Simply added back manually.
    
    $step9="1".bc_base58_encode(bc_hexdec($step8));
    echo "step9 ".$step9."<br><br>";
    
    ?>
    
    function hexStringToByteString($hexString){
        $len=strlen($hexString);
    
        $byteString="";
        for ($i=0;$i<$len;$i=$i+2){
            $charnum=hexdec(substr($hexString,$i,2));
            $byteString.=chr($charnum);
        }
    
    return $byteString;
    }
    
    // BCmath version for huge numbers
    function bc_arb_encode($num, $basestr) {
        if( ! function_exists('bcadd') ) {
            Throw new Exception('You need the BCmath extension.');
        }
    
        $base = strlen($basestr);
        $rep = '';
    
        while( true ){
            if( strlen($num) < 2 ) {
                if( intval($num) <= 0 ) {
                    break;
                }
            }
            $rem = bcmod($num, $base);
            $rep = $basestr[intval($rem)] . $rep;
            $num = bcdiv(bcsub($num, $rem), $base);
        }
        return $rep;
    }
    
    function bc_arb_decode($num, $basestr) {
        if( ! function_exists('bcadd') ) {
            Throw new Exception('You need the BCmath extension.');
        }
    
        $base = strlen($basestr);
        $dec = '0';
    
        $num_arr = str_split((string)$num);
        $cnt = strlen($num);
        for($i=0; $i < $cnt; $i++) {
            $pos = strpos($basestr, $num_arr[$i]);
            if( $pos === false ) {
                Throw new Exception(sprintf('Unknown character %s at offset %d', $num_arr[$i], $i));
            }
            $dec = bcadd(bcmul($dec, $base), $pos);
        }
        return $dec;
    }
    
    
    // base 58 alias
    function bc_base58_encode($num) {   
        return bc_arb_encode($num, '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
    }
    function bc_base58_decode($num) {
        return bc_arb_decode($num, '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
    }
    
    //hexdec with BCmath
    function bc_hexdec($num) {
        return bc_arb_decode(strtolower($num), '0123456789abcdef');
    }
    function bc_dechex($num) {
        return bc_arb_encode($num, '0123456789abcdef');
    }
    
    step1 0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
    step2 600ffe422b4e00731a59557a5cca46cc183944191006324a447bdb2d98d4b408
    step3 010966776006953d5567439e5e39f86a0d273bee
    step4 00010966776006953d5567439e5e39f86a0d273bee
    step5 445c7a8007a93d8733188288bb320a8fe2debd2ae1b47f0f50bc10bae845c094
    step6 d61967f63c7dd183914a4ae452c9f6ad5d462ce3d277798075b107615c1a8a30
    step7 d61967f6
    step8 00010966776006953d5567439e5e39f86a0d273beed61967f6
    step9 16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM