我试图遵循使用PHP将65字节公钥转换为比特币地址所需的指令。说明非常明确。任何人都可以帮助我在PHP中实现这一点的实用性?
说明是
1 - 获取用它生成的相应公钥(65字节,1字节0x04,32坐标对应X坐标,32字节对应Y坐标)
0450863在弱1F1 AD 403中添加4个间隙Sabkhafa 486 D 11 11 04887隐藏
2 - 对公钥执行SHA-256哈希处理
600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408
3 - 对SHA-256的结果执行RIPEMD-160散列
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 - 在RIPEMD-160散列前添加版本字节(主网络为0x00)
0 0 0 0 0 0 0 0
5 - 对扩展的RIPEMD-160结果执行SHA-256哈希
445头足类动物007
6 - 对先前SHA-256哈希的结果执行SHA-256哈希
点1967,然后选择183914A4E452Saft.Use 462Head
7 - 获取第二个SHA-256哈希的前4个字节。这是地址校验和
出售二手1967 - 手动
8 - 在点4的扩展RIPEMD-160哈希结尾处从点7添加4个校验和字节。这是25字节的二进制比特币地址。
0 0 0 0 0 0 0 0 0
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>";
这在第一步失败了。任何帮助赞赏。
这是输出
step1 0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
step2 32511e82d56dcea68eb774094e25bab0f8bdd9bc1eca1ceeda38c7a43aceddce
step3 7528c664cdc34c5ce809778eb688d32f89a538c0
step4 007528c664cdc34c5ce809778eb688d32f89a538c0
step5 86e76f4ff0bf0387339ac70a552e0fed615f7def34cc4809df1429e243f6c1fa
step6 b885b7225b370e7ff27ee0afb4f89b52b8675d5dc342d63de3abe7535f86cadb
step7 b885b722
step8 007528c664cdc34c5ce809778eb688d32f89a538c0b885b722
step9 1
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);
}
感谢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>";
?>
hash需要字节字符串而不是十六进制字符串。 hexStringToByteString是
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;
}
基本转换(感谢Sammitch - 修改为使用比特币base58)
// 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
仔细查看您的变量名称。 $ publickey与$ publicKey不同 - 注意大小写。
你的问题如下:
$checksum=substr($step6,0,4);
应该是$checksum=substr($step6,0,8);
,因为你需要两个十六进制字符来表示一个字节。$step8=$step4+$checksum;
应该是$step8=$step4.$checksum;
另外,我不知道你的base58_encode()
函数来自哪里,但我希望它使用BCmath,因为00ba084d3f143f2896809d3f1d7dffed472b39d8de7a39cf51
[步骤8的结果]所代表的数字太大,PHP无法在内部处理。
我今天在工作上非常无聊,这里是我的转换代码,奖金为BCmath,对于巨大的[比方说,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";
不要将base_convert()
用于这么大的数字,它似乎是不可靠的。我正在编写必要的bc_arb_decode()
对应物,发现输入和输出使用base_convert()
与arb_convert($num, '0123456789abcdef');
不同,并且在将结果与Wolfram Alpha进行比较后,似乎PHP错误地转换了数字。
Hex: 00ba084d3f143f2896809d3f1d7dffed472b39d8de7a39cf51
PHP's decode: 4561501878697786606686086062428080084446806606846864824262
Mine: 4561501878697784703577561586669353227270827349968709865297
Wolfram Alpha: 4561501878697784703577561586669353227270827349968709865297
你可以看到PHP已经过时了。 [1.9E42又名1.9 quintillion septillion]我已更新我的代码以包含arb_decode()
函数,这些函数似乎正确地执行了操作。
很重要!
替换为:'123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
有了这个:'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
在这里使用错误的代码将导致比特币交易失败或更糟,导致硬币消失到幻影钱包,在那里永远无法检索。
我不是开发人员,但我确认了更正。 Base58符号图表在这里,https://en.bitcoin.it/wiki/Base58Check_encoding
我在这里检查了我的工作http://brainwallet.org/
输入密码:“测试地址”,不带引号。
公钥是:047969a753f71135d4c792f384e546cd508514024b4ee40d12a014019b77d1b292763dfb8a108cf7a7119f80ca4a06e81b92464f5d8a7544d52cd2e641023a96d7
您的地址结果:1gBG1mbVtyNTgGZhggJ21A6mnjbNtqPCSr
我的结果:1Gch1MBvUZotGhzHGGj21b6MNKBoURpdsS
brainwallet.org结果:1Gch1MBvUZotGhzHGGj21b6MNKBoURpdsS
我希望这可以节省一些耗时或代价高昂的错误。