就像我们在银行的账户密码一样,比特币的一个账户的所有权是由与账户相关的三个核心概念决定的:私钥、公钥和比特币地址。比特币和交易与之息息相关。
(1)私钥、公钥和钱包地址(比特币地址)的关系
每个比特币钱包包含一系列密钥对,每个密钥对包括一个私钥和一个公钥。私钥(k)是一个数字,通常是随机选择的。有了私钥,我们可以通过使用椭圆曲线乘法的单向加密函数来生成公钥(k)。有了公钥(K),我们可以使用单向加密哈希函数来生成比特币地址(A)。
事实上,比特币地址可以被视为一种公钥。
它们之间的关系如上图所示。私钥可以通过椭圆加密算法生成公钥,公钥可以通过哈希函数生成比特币地址。相反,无法从比特币地址推断出公钥,也无法从公钥推断出私钥,这是通过后面要介绍的非对称加密算法来实现的。
值得一提的是,掌握了私钥就可以生成相应的公钥和比特币地址(钱包地址),相当于掌握了整个账户,所以一定要保管好自己的私钥。
(二)生成私钥、公钥和钱包地址(比特币地址)的流程图:
1.首先,使用随机数生成器生成一个“私钥”。一般来说,这是一个256位的数字。有了这一串数字,就可以操作对应“钱包地址”里的比特币,所以一定要安全存放。
2.SECP256K1算法对“私钥”进行处理,生成“公钥”。SECP256K1是一种椭圆曲线算法。当私钥已知时,可以计算公钥,但当公钥已知时,私钥不能反过来计算。这是保证比特币安全性的算法基础。
3.和SHA256一样,RIPEMD160也是一种哈希算法。“公钥散列”可以从“公钥”中计算出来,但反过来是不可行的。
4.将一个字节的地址版本号连接到“公钥哈希”的头部(该字节对于比特币网络的pubkey地址为“0”),然后对其进行两次SHA256运算,将结果的前四个字节作为“公钥哈希”的校验值连接在其尾部。
5.用BASE58(比特币定制版)对上一步的结果进行编码,得到“钱包地址”。
比如1a 1 ZP 1 EP 5 qgefi 2 DMP TTL 5 slmv 7 div FNA
(3)加密算法在比特币钱包和交易中的应用场景。私钥用于生成公钥和钱包地址,还用于签署交易。拥有“私钥”就意味着拥有这个钱包余额的所有操作权限。
(1)使用“私钥”对交易进行签名
比特币之间的转移是通过交易实现的。交易数据由被转移钱包的“私钥”所有者生成,也就是说有了“私钥”,钱包的比特币余额就可以花掉了。生成交易的过程如下:
1.交易的原始数据包括“转账金额”和“转入钱包地址”,但仅有这些是不够的,因为无法证明交易的生成者有权使用“转出钱包地址”的余额。因此,需要用“私钥”对原始数据进行签名。
2.生成“钱包公钥”。这个过程和第二步生成“钱包地址”一样。
3.在原始交易数据中添加“转出签名”和“转出公钥”,生成正式交易数据,这样就可以广播到比特币网络进行转账。
(2)使用“公钥”验证签名
交易数据广播到比特币网络后,节点会检查交易数据,包括签名的验证。如果核对无误,则余额将成功从“钱包外”转入“钱包内”。
(四)生成私钥、公钥、比特币地址的示例代码。椭圆加密算法使用的是大蟒的ecdsa库,哈希算法使用的是hashlib。另外没讲到的部分是base58Checkencode,这是在表示比特币地址时所用的方法,可以把地址压缩得更短,使得表示更为清晰。
(1)首先需要通过终端安装ecdsa包(椭圆加密算法库)。
Linux操作系统操作系统系统:sudo pip安装ecdsa
Windows操作系统操作系统系统:直接下载源码安装。
(2)Python代码:(windows,python2.7 idle)
# -*-编码:UTF 8-*-
导入ecdsa
导入ecdsa.der
导入ecdsa.util
导入哈希里布
导入操作系统
进口关于
导入结构
b58=\’ 123456789 abcdefghjklmnpqrstuvwxyzabcdefghijkmnopqrstuvwxyz \’
def base58编码(n):
结果=\’ \’
而n 0:
结果=b58[nX]结果
n /=58
回送结果
定义基数256解码:
结果=0
对于s中的丙:
结果=结果* 256订单(三)
回送结果
def countLeadingChars(s,ch):
计数=0
对于s中的丙:
如果c==ch:
计数=1
否则:
破裂
返回计数
def base58CheckEncode(版本,有效负载):
s=chr(版本)有效负载
校验和=hashlib。sha 256(hashlib。沙256(南).文摘().摘要()[0:4]
结果=s校验和
leadingZeros=countLeadingChars(结果,\’ \\0 \’)
返回\”1\”*前导零基本58编码(基本256解码(结果))
def privateKeyToWif(key_hex):
返回base58CheckEncode(0x80,key_hex.decode(\’hex \’))
定义privateKeyToPublicKey:
sk=ecdsa .签名密钥。from _ string(s . decode(\’ hex \’),curve=ecdsa .SECP256k1)
vk=sk.verifying _ key
返回(\’ \\ 04 \’ sk。正在验证_ key。to _ string()).编码(\”十六进制\”)
定义公共密钥地址:
ripemd 160=hashlib。新的(“ripemd 160”)
ripemd 160。更新(hashlib。sha 256(s解码(\’ hex \’)).digest())
返回base58CheckEncode(0,ripemd160.digest())
定义密钥地址:
返回pubKeyToAddr(privateKeyToPublicKey(s))
#生成随机私钥
private_key=os.urandom(32).编码(\”十六进制\”)
\”打印\”秘密指数(未压缩):%s \’ % private_key
\”打印\”公钥:% s \’ % privateKeyToPublicKey(private _ Key)
\”打印\”私钥:% s \” % privateKeyToWif(Private _ Key)
\”打印\”地址:% s \” % addr的密钥(private _ key)
(3)输出: