比如1HUBHMij46Hae75JPdWjeZ5Q7KaL7EFRSD
,这个地址,有转出过,如何得到公钥
原理很简单,但是实践起来比较烦:
首先我们找一下这个地址的随便一笔花费,比如这个:
https://btc.com/0998ef06442994c147aec242e6973dfe3d512b05bde880793051a48bd021fc33
然后需要一个工具通过交易hash解析一下这笔交易
推荐用这个 libbitcoin/libbitcoin-explorer
执行
bx-windows-x64-icu.exe fetch-tx 0998ef06442994c147aec242e6973dfe3d512b05bde880793051a48bd021fc33
得到了这笔交易解析后的完整输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| transaction
{
hash 0998ef06442994c147aec242e6973dfe3d512b05bde880793051a48bd021fc33
inputs
{
input
{
address_hash b4a5d3960471568c3883046eec3b41b4953d61a1
previous_output
{
hash 5fb9f0e7f520163e4afe0baa440fe93999273e95d9e345e0488a0802ed62674f
index 0
}
script "[3045022100e4a4695ecbe6f507ec7181a2f321f489c7a3bd7eea032c75e4e1eba89174183c022019555aa917be6191db14da72e5c234a4b628f321b917ea334bcf9c122296cd5901] [044da006f958beba78ec54443df4a3f52237253f7ae8cbdb17dccf3feaa57f3126da0a0909f11998130c2d0e86a485f4e79ee466a183a476c432c68758ab9e630b]"
sequence 4294967295
}
}
lock_time 0
outputs
{
output
{
address_hash c621cbfd778e6109e26046d96738c7af75e7b78b
script "dup hash160 [c621cbfd778e6109e26046d96738c7af75e7b78b] equalverify checksig"
value 43103
}
}
version 1
}
|
注意script那一段,就是分成了两部分,前面一个中括号里面是签名,后面是公钥。
然后仔细看看这还是个老钱包生成的地址,没有压缩;
写个小脚本parse一下这个公钥,就可以看看是不是和地址对应啦:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #!/usr/bin/env python
from hashlib import *
from base58 import *
def SHA256D(bstr):
return sha256(sha256(bstr).digest()).digest()
def ConvertPKHToAddress(prefix, addr):
data = prefix + addr
return b58encode(data + SHA256D(data)[:4])
def PubkeyToAddress(pubkey_hex):
pubkey = bytearray.fromhex(pubkey_hex)
round1 = sha256(pubkey).digest()
h = new('ripemd160')
h.update(round1)
pubkey_hash = h.digest()
return ConvertPKHToAddress(b'\x00', pubkey_hash)
pubkey = "044da006f958beba78ec54443df4a3f52237253f7ae8cbdb17dccf3feaa57f3126da0a0909f11998130c2d0e86a485f4e79ee466a183a476c432c68758ab9e630b"
print(len(pubkey))
print("Address: %s" % PubkeyToAddress(pubkey))
|
输出是这样的:
1
2
| 130
Address: 1HUBHMij46Hae75JPdWjeZ5Q7KaL7EFRSD
|
OK,打完收工。
如果一个地址只收币,从来没消费币,公钥是不会广播到网上的,所以这种地址拿不到公钥。一定要有花费,才能得到公钥。
所以有人推荐每次花费币之后就不要再用老地址了,每次交易都用新地址,避免将来出现什么黑科技(比如量子计算机之类的)穷举破解。 其实我觉的无所谓,大不了有人喊ECDSA挂了我再转移一下就行了,人家富豪榜里面都有好几个大佬也不在乎这点事。
PS:更新自打脸一下,我还是觉得每次交易用新地址是一定要做的,理论上HASH碰撞的概率有2^160,但是我现在觉得这个量级不能简单的推算为1/2^160;毕竟不是所有的钱包实现熵值都足够大。尽可能每次交易用新地址会增加碰撞库更新的难度。
再强调一遍,每次交易用新地址是一个必须养成的习惯。
另外公钥有两种形式:压缩与非压缩。一把私钥其实可以搞出两个地址哈。早期比特币均使用非压缩公钥,现大部分客户端已默认使用压缩公钥。早期openssl库的文档写的比较糙,导致Satoshi以为必须使用非压缩的完整公钥,后来大家发现其实公钥的左右两个32字节是有关联的,左侧(X)可以推出右侧(Y)的平方值,有左侧(X)就可以了。