26 June 2018

第二部分:跟我一步一步看懂比特币现金(BCH)的交易(2)

第四章. 私钥,公钥和地址


这一章主要介绍一下BCH几个最基本的概念,理解了这些概念,才能弄懂第四章要讲的交易脚本和UTXO。

哈希

哈希是英文hash的音译,也译作散列,是一种摘要算法,能把任意长度的字符串压缩成一个固定长度的字符串,相当于提取了这个字符串的一段“指纹”,哈希后的字符串会损失很多信息,也就是说原字符串可以推导出hash后的字符串,但是hash后的字符串无法推导出原字符串。

举个好理解的例子,比如一个汉字“币”,我们提取它的笔画数:4画,这就是一种哈希算法,笔画4就是“币”这个字的信息摘要,或者说把“币”简化成了4这个数字。已知一个汉字,很容易算出它的笔画数,但是已知汉字笔画数,却无法推导出原汉字,原因很好理解,因为哈希过程丢失了原汉字的很多信息。

而且,笔画数是4的汉字有很多,比如“王”、“天”等等,不同的输入(汉字),产生了相同的散列值(笔画),这就叫哈希碰撞,或者叫散列冲突,好的哈希算法应该很难找到冲突的输入,hash值分布的很均匀,上面那个数汉字笔画的算法很容易找到产生碰撞的值(汉字),所以不是一个好的hash算法。

好的哈希算法就像把一个瓶子摔碎,摔得很碎很碎,摔成粉末状,然后随机取其中256粒粉末,记住它们的相对位置,作为这个瓶子的“指纹”,如果只知道这256个颗粒,肯定拼不出最初的瓶子,但这些颗粒已经基本能代表这个瓶子了。理论上如果有无数个瓶子让你摔,总能找到两个(实际上能找出无数个)摔出来的粉末分布完全相同的瓶子(产生哈希碰撞),但你可能摔到宇宙毁灭的那一天也碰不到一个。

比特币的地址就是由比特币的公钥通过哈希算法得出的。

地址

BCH的地址类似这样:

bitcoincash:qz42k7xu32e3gn9wauujznnu064p7d85zqt0ntl3fu (就是上一章交易号为 a8e02… 的那笔交易的输入)

这是新的BCH地址格式,完整的BCH地址以“bitcoincash:”开头,但通常会省略开头的字符,只显示冒号后面的字符,如果多观察几个地址,可以发现后门的字符都是以q开头的。

最初BCH的地址格式和经典比特币地址是一样的,都是以1开头,类似:

1GZRHhkZP8RmvDAgvECE6ZmVoK92G67aVR

这两个地址表面上差异很大,其实代表的是同一个地址,它们之间是可以互相转换的,可以通过下面这个在线工具进行地址转换:

https://bch.btc.com/tools/address-converter

之所以会出现两种地址格式,是因为BCH刚分裂出来的时候,因为BCH和BCE的地址通用,经常有人转错地址,比如把BCH转到BCE地址上,或者把BCE转到BCH地址上,造成很大麻烦,甚至丢币,所以BCH的开发者设计了新的地址格式,这样就可以避免转错。可惜目前还有很多交易所和钱包不支持新的BCH地址,这个过度可能需要较长一段时间。还有的人不喜欢新的地址格式,这个就是仁者见仁,智者见智了。

如果你试了那个在线转换地址的工具,会发现还有第三种地址格式:BitPay & Copay 的格式,BitPay是一家提供企业级比特币支付解决方案的公司,被称作比特币上的PayPal,但是我并不理解他们为什么要自己搞一个新的地址格式。

公钥

讲“哈希”的时候我已经提过了,比特币的地址就是由比特币的公钥通过哈希算法得出的,比特币的公钥是一个65字节长的字符串(65*8=520个0和1组成),一般用16进制表示,620/4=130个16进制数,例如:

04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235

公钥经过2次哈希运算,还经过一些变换,就得到比特币的地址。

第一次哈希叫做SHA-256,第二次哈希叫做RIPEMD-160,这一过程统称“双哈希”或“Hash160”,做完这一步还没完,要生成我们最终看到的那个地址,还有好几个步骤,以经典比特币地址为例,还要加入版本信息,加入校验信息(这个校验信息主要是取前一步运算结果然后通过2次SHA-256哈希再取前4个字节得到的),然后再进行一次Base58编码最终得到我们常见的比特币地址(Base58编码是一种二进制转可视字符串的算法,为了便于人类阅读,去除了几个看起来会产生歧义的字符,如0和o)。

那么公钥又是怎么得到的呢?是通过非对称加密算法得到的。下面就要介绍一下非对称加密算法。

非对称加密算法

传统的加密算法需要信息发送者和接受者提前商定一个秘钥,然后发送者用这个秘钥对信息加密,接受者收到加密信息后,用相同的秘钥进行解密,这种加密算法被称作对称加密算法,对称加密有个最大的问题,就是双方必须对秘钥进行传输,这无疑大大增加了秘钥泄漏的可能性,于是有两个密码学家在1976年发明了非对称加密算法。

非对称加密算法又叫公开秘钥加密算法,一个人(比如叫Alice)可以通过非对称加密算法生成两个秘钥,一个叫公钥,一个叫私钥,私钥自己保存,不能透露给任何人,公钥可以对外广播。Bob如果想给Alice发送加密信息,他可以用Alice的公钥对信息进行加密(加密算法是公开的),然后把加密信息发送给Alice,Alice收到信息后用手中的私钥进行解密,得到明文。只有对应的私钥才能解开公钥加密的信息,并且已知公钥是很难猜出私钥的,最重要的是发送和接受者之间不用传递秘钥信息,所以要比对称加密算法安全很多,比特币就是在非对称加密算法的基础上实现的。

公钥和私钥的加密运算是可以互逆的,我们可以用公钥和明文进行运算得到密文,这一过程叫加密,然后用私钥和密文进行运算得到明文,这一过程叫解密。也可以反过来,用私钥和明文进行运算得到密文,只是这一过程不叫加密,叫签名,然后用密文和公钥进行运算,得到明文,这一过程不叫解密,叫验证。

签名和验证有什么用呢?它可以证明某一段信息是不是我本人发出的,比如我想向某人证明某一个BCH地址中的100个BCH是我本人拥有的(我当然不能直接把币转给他),我可以让对方写下一句话,比如对方说“这个地址的BCH是属于炒鸡蛋的”,然后用这个地址的私钥对这句话进行签名,告诉对方签名结果。对方可以用这个地址的公钥对签名进行验证,如果解密后的明文确实是“这个地址的BCH是属于炒鸡蛋的”,就证明我掌握了这个地址的私钥,这100个BCH是属于我的。

非对称加密算法有很多种,BCH使用的加密算法叫椭圆曲线加密算法。

椭圆曲线加密算法

椭圆曲线加密算法涉及比较深的数学知识,我也不能完全理解,一般只需要大概的原理即可。

首先需要生成私钥,最早的私钥是1字节版本号+一个32字节的随机数,再进行Base58编码得到的。

比特币可用的私钥是一个非常非常大的数,略小于2的256次方,两次运算生成相同随机数的可能性约等于0,所以可以认为每个私钥都是唯一的。

下一步就是利用椭圆曲线加密算法计算公钥,公钥是65字节,可以把公钥想象成一个对称的曲线图形,中间有一点是固定的,这个点左边的图形和右边是对称的,也就是说知道了左半边可以推出右半边,反之亦然。65字节中有一个字节0x04是固定的,然后左边32字节和右边32字节是对称的,也就是说这65个字节是可压缩的,只需要知道其中 32+1 = 33字节即可。

支持压缩的比特币的私钥是34字节,由 1字节版本号+32字节随机数+是否支持压缩 组成,转成Base58编码后,一般是以L或者K开头。

有了公钥,我们就可以用前面提到的双哈希算法生成地址了。

最后总结一下:“私钥”通过“椭圆曲线加密算法”生成“公钥”,“公钥”通过“双哈希”生成“地址”,这个过程是不可逆的,已知地址,不能得到公钥,已知公钥不能得到私钥(至少目前不行)。

下面一章介绍BCH最有意思的部分:交易脚本和UTXO。