从理性的角度重新认识一下比特币到底是如何运作



妈咪说知识就是力量大家好我是妈咪叔,上期咱们从感性层面理解了一下什么是比特币,接下来咱们再来从理性的角度重新认识一下,比特币到底是如何运作的呢?
就是我们来研究它的逻辑,上期讲完了之后受到了一些比特币用户的强烈抗议,你怎么能说我们的比特币是游戏币呢?
很好这就是针对一件事儿不能达成共识,共识也是区块链里,或者说是分布式系统当中一个很重要的概念,当然和通常理解的共识还不太一样,那先问个小问题,你觉得在所有学科当中最容易达成共识的是什么呢?
肯定不是经济学了经济学有很多学派的,也不是物理是数学,1+1=2全世界都认可,那今天咱们就来看数学是如何应用在比特币当中的,今天我们先来说密码学的部分好开始正题,我们说你可以把比特币系统当做一款游戏,那游戏肯定需要有客户端,这个客户端可以有很多版本,比如说官方提供的也可以由一些第三方公司来提供,我们如果在官网下载一个那就是长这样的,这就是官方的比特币钱包,而且不用你自己注册账号,只要客户端安装之后它就会自动给你生成三个东西,私钥、公钥和地址,其中私钥和公钥一般情况你自己是看不到的,在系统中会以一个wallet.dat的文件体现,地址是比较开放的地址就相当于你的银行卡号,你让别人给你转账你肯定得把账号告诉他吧,而私钥就相当于是每个人的密码,有了密码就代表你拥有了这个账号的控制权,很好理解对吧,可是比特币的私钥这个密码是不允许用户修改的,但是你可以生成很多个,而且它和你的账号之间还会存在一些关联,简单说就是通过私钥生成公钥再通过公钥生成地址,但是注意这个过程是单向的想要反推回去做不到,那咱们就先来说一下私钥、公钥和地址是如何产生的呢?
首先系统会为你随机生成一个256位的二进制数,比如说这个,注意这是随机生成的,这一串二进制数就是你的私钥一共是32个字节,那如果我们把它转换成16进制就长这样,私钥这就有了,256位二进制数可以表示多少个数呢?
2^256个数对吧,换算成十进制有多少呢?
大概是10^77这么多天文数字,所以如果选用好一点的随机数发生器,完全不用担心私钥会重复的问题,那公钥是如何产生的呢?
公钥就不是随机生成的了,而是在这个私钥的基础之上通过算法得来的,这个加密算法叫做ECDSA椭圆曲线数字签名算法,具体怎么算咱们来简单说一下,说有这样一个方程y^2=x^3+ax+b,其中a、b为实数且-16(4a^3+27b^2)≠0,这个就是判别式△,这个方程的图像就叫做椭圆曲线Ellipticcurve,它属于魏尔斯特拉斯方程,根据系数a、b取值的不同函数图像大致是长这样的,虽然叫椭圆曲线但是它明显不是个椭圆,利用这个曲线来加密就叫做椭圆曲线密码学,EllipticCurveCryptography简称ECC,比特币当中使用的具体的算法就是ECDSA属于ECC,具体怎么加密呢?
其实就是我随机在这个图像上选取一个点,这个点有个坐标吧比如说点A(x,y),然后把我的私钥k分别和x、y相乘得到kx和ky,再把kx和ky拼接在一起就行了,注意这不是加法而是拼接合起来,得到的结果就是公钥假设是p,当然实际情况不会这么简单,这里解释两点第一,刚才我们说的相乘不是通常意义上的相乘,而是新定义的乘法叫做椭圆乘法,什么意思呢,k乘以点A就相当于是有k个A点相加对吧,那我们就先要定义点与点的加法,假设这是点A这是点B,我们定义A+B等于AB的连线交曲线于另一点这是点C,还不行还要做出点C沿x轴的对称点,这个点就是A+B了,很奇怪的算法是吧,实际上这就是定义了一个阿贝尔群,这块各位不用管了,那如果是A+A呢?
那就没有连线了,没关系那就用A点的切线交曲线于另外一点,然后再做x轴的对称点这点就是A+A,如果再加一个A呢?
这回就有连线了就是这个交点的对称点,这个点就是A+A+A也就是3A以此类推,那kA什么意思呢?
就是要重复上述操作k次,得到的结果就构成了公钥p,所以公钥其实就是一个特定椭圆曲线上的坐标点,那有同学可能会好奇,哇塞重复k次这个k可是私钥啊,重复这么多次电脑会很快给出结果吗?
会为什么,因为根本不用重复k次,看这这个点是2A对吧,我不用再加A去求3A,我可以直接做切线,这个交点的对称点是什么啊?

这就是4A,然后再做切线就会得到8A然后16A,你看指数增长,那k最大也就是2^256呗,所以最多两百多次就可以得到kA的结果,能想明白不?
那为什么从公钥不能推出私钥呢?
因为最终你得到的公钥只是一个点,至于这个点的来源你是不知道的可以有很多,我们之前说过这类函数叫什么啊?
叫Trapdoorfunction活板门函数就是单向函数,包括之前说过的RSA算法,ECC算法其实要比RSA算法来的更快而且更安全,那好第二点要解释的,这个图像上明显有无数个点啊,那我如果选择一个很简单的点和私钥相乘,得到的公钥就会很鸡肋,所以我们要对这个点提出一些要求,不能太简单,这个要求是把这条椭圆曲线定义在某个质数阶的有限域上,这块说起来有点复杂各位了解一下就行了咱们快速带过,简单说就是把这个椭圆曲线给打散了,不是连续的曲线了而是一些离散的点,比如说这是一个方格,这个方格的长度就是阶数也就是这个质数P,然后这里面有很多离散的满足要求的点,但是计算规则是一样的,点A+点B还是画出连线交第三点C然后再做对称点,这就是A+B,唯独不同的是,如果AB的连线走到这还是没有交点怎么办呢?
不能画出去了这是个有限域,没关系就从下面的对称点继续往上画直到相交第三点为止,能大概明白什么意思吧,其中这个质数P越大越好越安全,这样我们以比特币为例,比特币使用的是secp256k1标准,所谓标准就是说我要给你规定具体用哪个椭圆曲线,也就是给出系数a、b的具体值,还有这个大质数具体是多少,以及满足以上要求的一个基准点G的坐标,什么意思呢这个标准中规定a=0b=7,所以比特币中使用的椭圆曲线方程就是y^2=x^3+7,这个函数图像在实数上的图像长这样,可是这个不能用因为需要在一个质数阶的有限域内,标准中规定这个大质数P=2^256-2^32-2^9-2^8-2^7-2^6-2^4-2^0,用16进制表示它长这样,这个数是一个质数而且显然它很大,所以呢这个曲线就变成了这么多阶的方格子中的离散点,然后在这些点中选取一个基准点G点,这个G点就可以用来计算公钥了,同样在secp256k1标准中也是公布出来的,G点的具体坐标是这也是16进制的表示,这是横坐标这是纵坐标,显然它是一个很大很大的点,注意所有人使用的G点都是一样的,只是每个人的私钥不同而已这是写在代码里的,这样一相乘就得到了自己的公钥p了,其中x坐标是32个字节y坐标也是32个字节,所以公钥有多少字节呢?
是65个字节多出的一个字节是标识位0x04,主要说明这是16进制,好了说了一大堆这个私钥和公钥可以干啥呢?
就是用来非对称加密的啥叫非对称啊,就是指加密和解密的钥匙不是同一个,这是相对于对称加密来说的,比如说Alice想要发给Bob一个消息m,双方规定密码就是+1操作解密就是-1操作,那Alice只需要计算出m+1=n,然后把n发送给Bob,Bob收到n之后用n-1就会得到m了,这就是对称加密,那非对称加密怎么实现呢?
咱们回忆一下,私钥K是怎么来的啊?
随机来的,公钥P是怎么来的啊?
是私钥k乘以一个G点来的,这个G是约定好的你可以把它当做一个常数,谁都可以知道没关系,重点就在于这个式子了,这个式子有两个特点直接决定了非对称加密的两大用途,咱们来看哪两个特点,第一如果知道P值G还是常数那也很难求得k值,好理解吧单向函数嘛,第二虽然k值难求,不过对于给定的k值你可以在多项式时间内进行验证,说白了很好验证,啥意思啊这不就是一个NP问题嘛,比如说咱们之前说过的,应用在RSA当中的大数质因数分解问题,问319是哪两个质数的乘积?
这就很难算,但是如果我问29*11等不等于319啊?
这就很好验证,所以对应具体的两个应用就是,第一数据加密,原理是这样,现在Alice有自己的一对公私钥Ka和Pa,Bob也有自己的一对Kb和Pb,公钥是对外公开的私钥是不能告诉别人的,所以Alice可以知道这样一个数,就是自己的私钥Ka乘以Bob的公钥Pb,同理Bob也可以知道自己的私钥Kb乘以Alice的公钥Pa,那咱们来看这两个分别等于什么,(上面等于Ka*Kb*G),(下面等于Kb*Ka*G),括号打开这两个等式实际上是相等的,那我们就可以把它看做是一个针对于两个人的对称秘钥了,假设是key,那双方不管传输什么都和万能key去做可逆运算就可以了,能明白不?
所以为什么说A加密需要B的公钥呢?
同理B加密要用到A的公钥呢?
就是这个式子决定的,第二个作用就是所谓的数据签名,就是我要证明我说的话是我说的怎么证明呢,比如说我要对数据m进行签名,以代表我对m的认可,那我就可以用m乘以我的私钥k,得到一个结果假设是N,这个N就叫做签名数据,对了注意啊咱们刚才说的乘法都表示群乘法啊,你就把它当做一种运算就行了,那这个运算和乘以点G是相同的,也是不可逆的单向的,然后别人想要验证这句话m是不是我说的,那就用m乘以我的公钥P,它应该等于m乘以G再乘以K,其中G是常数,mK就是N我发布的签名啊,所以你可以很快的验证这两个结果是不是相等的,这就是数字签名的大致原理,所以比特币当中的公私钥为什么要有关联,就是因为要进行非对称加密,好下面来说地址,比特币的地址是由公钥经过两次哈希运算得到的,什么叫哈希运算呢?

学过编程的同学肯定不陌生了,也叫做散列函数Hashfunction,它的功能是可以给任意长度的数据生成指定长度的字符串,注意是任意长度的数据,比如说在比特币中广泛使用的SHA-256函数,这是第二代哈希函数(SHA-2)其中的一个,这个函数不管你放进去什么,都会输出一个长度为256个bit的字符串,一般叫做摘要或者叫哈希值,哈希函数具有以下这么几个特点,首先它的计算速度比较快,即便你把莎士比亚全集都放进去,也会很快的生成一个摘要,第二确定性,就是说只要你输入的内容是相同的,那么经过同一个哈希运算不管多少次,都会得到相同的结果,这是必须的,要是每次结果都不同那不就是随机数了么,那就是在逗我们玩了,与之相对的一个特点就是随机性,不过这个随机性指的是,只要两次输入的内容稍稍有一点不同,那么结果就会面目全非,这几个属性先来直观的给不了解编程的同学演示一下,什么意思,这段代码就是对于SHA-256函数的执行,现在是即将执行三个SHA-256函数,看这个引号里面就是我输入的内容,现在这三个输入都是相同的,我们来执行看一下,可以看到只要内容相同结果就是相同的,这就是确定性,那我把其中一个数据改动一点点,比如说我把这个大T改成小写的t,这个改动很小吧那咱们再来执行一下,你看这个结果就变得面目全非了,但一定是256个比特,这个输入里面放什么都可以多长都可以,明白了吧,这个特点可以干啥呢?
用来生成私钥私钥就是256个比特啊,其实现在很多客户端的随机私钥就是这么生成的,先是生成一个大随机数然后再取哈希值,那就有个问题了,理论上输入可以是无限大,但是输出却最多只有2^256个数,因为一共就256位,那会不会出现两个不同的输入,却得到一个相同哈希值的情况呢?
会而且是几乎必然会,这种情况就叫做哈希碰撞,所以一个好的哈希函数还需要满足一个特点叫做防碰撞性,说的是不存在一个快速的有效的办法,可以找到两个不同的输入却得到相同的哈希值,说白了有生之年每秒钟都在尝试哈希碰撞,那概率也是微乎其微,另外一个特点是单向性,很简单就是说从输入可以得到输出,但是从输出并不能得到输入,一定得这样要不然会怎么样啊?
那就相当于是找到了一个最强压缩方案了,因为任何数据不管多大进去之后都变成256个比特了,然后还能原封不动的还原回去,这不就是压缩和解压的过程嘛不存在的,所以哈希运算本身和加密没啥关系,和非对称加密就更没关系了,比特币的非对称加密就是由刚才说的ECDSA决定的,你看加密是为了啥?
是为了更安全的解密解密才是重点,就是你得还能还原回去,你的加密方案再好天花乱坠的,但是谁都解不开连你自己都解不开,那就不叫加密了那叫数据玩丢了,而哈希函数恰恰不具备这个特点所以它不能加密,那为什么比特币系统当中还会使用SHA-256函数呢?
因为虽然它不能加密,但是我可以通过哈希函数知道某个数据是否被篡改了,比如说之前流行的第一代哈希函数SHA-1当中的MD5算法,就是你可能见过某个软件的官网上会标注一个md5值,这个值就是对官方正版软件的一个摘要,如果你从未知来源下载了同一个软件,那么你就可以查看一下这个软件的md5,然后和官方给出的md5对比一下,就知道你下载的软件是否被篡改过了或者被写入木马了,这个方案挺好的对吧?
为啥不用了呢?
因为md5在04年的时候被我国的王小云教授破解了,09年又被中科院的冯登国、北大的谢涛教授再次破解,就是复杂度又降低了所以现在基本上被淘汰了,但是不用担心SHA-256函数目前还是安全的,怎么说到这来了,那咱们接着说公钥是如何生成地址的,首先就是对公钥进行SHA-256运算,然后将得到的结果再次进行一个哈希运算,叫做RIPEMD-160这也是一个哈希函数,只不过生成的摘要是160个比特的也就是20个字节,这个东西其实就是地址了,但是你可能会发现这串数字,好像和通常大家见到过的比特币地址不太一样,一般都是1开头的,对因为还差最后一道工序就是编码,所谓编码就是把一种格式转换成另外一种格式的过程,比如说我要把二进制转换成16进制,或者转换成10进制,再比如说计算机底层执行的都是一堆二进制1010,为什么我们看到的却是各种文字或者是图片甚至是视频呢?
就是因为经过了各种编码的过程,原理很简单这就是一个对称加密的过程,逆操作就叫做解码,举个例子,比如说BASE64编码,64就是说我想用64个字符来表示所有所有的信息,可以那就把想用的64个字符都列出来,再标上相应的序号,比如说有大小写英文字母一共52个,再加上0-910个数字一共是62个,还差两个那就用+和/来补充,然后有一串二进制数010011010110000101101110,怎么表示成我规定的这些字符呢?
一共64个字符,多少个比特可以表示64种状态呢?
2^66个比特就够了对吧,所以我就选取前6个bits,它对应了十进制的19,然后查一下这个顺序19是T,后面6个比特是22对应的是W,再后面6个是5对应的是F,最后6个是46对应的是u,所以这串二进制数用base64编码来表示就是TWFu,如果用英文的ASCII码编码这串数字表示什么呢?
ASCII码是8位一编,这8位对应十进制的77对应的ASCII码是M,这8位是97对应了小写的a,最后8位是110对应了小写的n,这就是编码,比特币当中使用的编码是BASE58,也就是说经过BASE58编码后的私钥和地址,最多只能出现58种字符这是中本聪自创的编码,哪58个字符呢?
就是在Base64的基础上,首先把+/这哥俩删了,然后不要数字0、大写字母O,大写字母I和小写字母l”,可能都是中本聪看着不顺眼的剩下的一共58个,可是这会出现问题,我如果用6个比特来编码就一定有不能表示的数据,如果用5个比特一编码就一定会有部分字符用不到,能想明白不?
比如说有个二进制是111111,这是多少啊?
十进制的63对吧,可是我一共就58个字符啊没法表示了,怎么办呢?
这个解决办法很巧妙,其实就是我不管你这一串数据是什么有多大,我统统转换成58进制然后我直接查表就行了,能明白不?
当然这是纯数学上的解决办法,实际在代码当中会有一些出入,这样我们通过Base58编码,就可以得到一般情况下看到的地址了,为什么大部分地址的开头都是1呢?
同样是因为在公钥的最前面加入了一个标识符,其实后面还要再加上一个双哈希的验证,这块咱们就不过多说了原理都一样,得到的这种格式叫做WIFWalletimportformat,钱包导入格式,好至此关于比特币的私钥、公钥和地址,在数学层面的产生方式咱们就说完了,其实讲比特币不是重点,重点咱们是为了说数学和密码学的一些原理,就像开篇说的有朋友表示抗议,可以,这就像是木匠打了一套家具,我只是木匠的小学徒,我是为了告诉大家这个家具是怎么打的这是一堆木头,可是你非说你胡说这明明是艺术品,那我也没办法可能我确实也没那个审美,好了今天就到这,我是妈咪叔一个较真儿的理工男,下期见拜拜。