比特币-加密,私钥,公钥,地址

原创 2018-04-04 17:24 阅读(134)次

比特币的安全主线是通过私钥生成公钥,公钥生成地址。由于这些过程大量使用了hash算法,所以无法反推出私钥,来保证比特币不会被盗取。


先说私钥生

私钥其实一组随机数,256位的二进制数,必须妥善保存。如果丢了或者给别人,那上面的比特币就丢失或者被别人支配了。这个256位的2进制的生成其实就是在1到2的256次方个数字(其实是略少于这个范围,有一些被排除了,因个数量已经超过了宇宙中原子的总数,想要遍历所有的私钥,耗尽整个太阳的能量也是不可能的)中选一个数字出来。这个数字的选取无法预测。不要用程序提供的简易随机数生成器来生成这个随机数,必须是密码学安全的伪随机数生成器

不要自己写代码或者用开发语言提供的随机方法来生成私钥,因为这样可能会不够安全。没有足够的熵值的种子而造成不够随机,容易被碰撞出来。

要用密码学安全的伪随机数生成器。

私钥的形式:

除了256位2进制数或者64位的16进制数外,还有两种:

WIF格式(Wallet Import Format):钱包导入模式,开头添加一个十六进制数80(十进制就是128),是base58编码的形式,5开头

WIF-compressed 格式 : 私钥在base58check编码后还会显示为K或者L开头的格式。

原因:虽然Base58编码版本前缀对WIF和WIF压缩格式都是相同的(0x80),但在数字末尾添加一个字节会寻致Base58编码的第一字符从5发为K或者 L。

这是表示私钥在转换成公钥的时候需要压缩,而在私钥尾部追加二进制数01造成的。要压缩加01,base58check后生成开头为K或者L的私钥。不压缩不要增加任何信息。

所以私钥的压缩格式(为了公钥压缩)其实私钥的数据是增加的。

两种不同的WIF格式虽然表示相同的私钥,但他们导入钱包的时候,因为生成的公钥不同,地址也就不同,钱包只会找对应的公钥和地址。

考虑到私钥安全性的问题,BIP0038提出用一个口令对WIF格式的私钥进行加密后再base58check编码,称之为加密私钥。这种格式的私钥开头为"6P"。钱包如果发现导入的私钥是6P开头,就会要求提供口令进行解密。

有了这种格式后,私钥可以"冷存储",比如记录在一张纸张上(纸钱包)。




私钥生成公钥

比特币用了椭圆曲线乘法作为他的公钥加密基础。这是一种数学上的算法,可以从以一个方向计算,但无法进行反推。

所以公钥就是用椭圆曲线算法作用于私钥得到的。大多数是用OpenSSL加密库来进行椭圆曲线计算。

所以公钥和私钥是一对,有私钥可以随时生成公钥,但公钥无法反推私钥。

公钥分压缩和非压缩格式,非压缩格式首先是开头添加类型version 十六进制数04,后面跟着2个256位二进制数(2*64位十六进制数),总是130位十六进制数。

压缩格式开头添加的类型version十六进制数是02,或者03,后面也是跟着1个256位二进制数(1*64位十六进制数),总是66位十六进制数。

为什么是2个256位二进制数,因为椭圆曲线生成的是一个坐标系上的(x,y) 的点。这2个点分别是256位二进制数。但因为知道x其实是可以求出y的,所以压缩格式省去了y的256位二进制数。

显然压缩格式比非压缩格式小了256位二进制数,这在交易时候传递的数据就减少了将近一半,是很有利的。显然将来都会是压缩格式。非压缩格式是为了兼容之前的比特币。

至于为什么有02,或者03两种前缀类型version,是因为椭圆曲线算法为了表示y的正负值。



公钥到地址

K是公钥,A是地址

A = RIPEMD160(SHA256(K))

地址是先对公钥进行SHA256,之后再进行RIPEMD160(两种hash算法)

但我们常看到的地址并不是A目前的格式(注意是另外的格式,另一种展示,并不是继续处理)。A会在经过 Base58check 处理得到base58checkA(他比A在前部增加了一个类型,也叫做版本,version,在后面增加了校验和),这样处理是后的三个好处:易读,压缩,错误检测。具体有兴趣去看base58check的博文。

在base58check处理前,会在A的前面增加一个表示类型是地址的两位的十六进制数00,所以经过base58check处理后,地址都会是以1开头。

但A和base58checkA,都是地址,只是不同的格式而已。

而且上面我提到K公钥可能是压缩格式或者非压缩格式,所以实际上生成的地址也会在双重hash之后得到不同的结果。但他们都对应着相同的私钥。

至于地址被base58check后应该是多少位的十六进制数呢?

RIPEMD160后是20个字节(160个二进制位),加上version的0x00,就是168位,加上base58check尾部加上的校验和是4个字节(32位),也就是200位二进制,base58check是每6位当成一个字符,所以200/6=33.33333, 除不尽,尾部补0,所以是34位字符。

本文完。



下一篇:Base64