理解区块链和比特币(二)

理解区块链和比特币(一)尽量简单地介绍了比特币网络的设计和运行流程,具体的一些细节并未并未做过多的纠缠。此外,比特币现在这种独特的设计虽然解决了问题,但是依然有一些不足。比特币之后又有许多基于区块链技术的数字货币和交易系统诞生,随之也诞生了非常多的“玩法”。这篇文章再讨论一下比特币网络的一些技术细节和发展。

交易验证的细节

在比特币的交易过程中,验证交易的真伪是一个非常重要的步骤,在理解区块链和比特币(一)中提到了验证交易真伪流程:

1. 用户X发起一个交易请求:[用户X 使用 [一笔存在的转账] 支付 金额S 给用户Y]+[用户X对这笔交易的数字签名]。
2. 在记录到账本上之前,需要验证这样几个事情:
    a. 这笔交易的数字签名是否真实有效。(用上一笔交易中的公钥解密签名,计算[交易内容+前一个交易]的hash值,判断这两个值是否相等)
    b. 查阅账本,查看资金来源未被用户X使用过。
    c. 检查交易是否合法:资金来源的支票的金额大于等于要支付金额。
3. 如果上述检查通过,所有人都同意交易合法,那么就在总账本上记下来。

这套流程为何能够保证交易的真伪?

非对称加密和数字签名原理

密码学提供了一套强有力的数字加密和签名验证的工具:非对称加解密。具体数学原理不在此讨论,但基本原则如下:

1.  存在一套一一对应的两把钥匙;
2.  可以用其中一把钥匙对一段文本进行加密。加密之后,*能且仅能*由另一把钥匙进行解密;
3.  我们把其中一把钥匙私藏,不对外公布,称为私钥;另一把钥匙对外公布,称为公钥。

有了这样的一对钥匙,除了可以实现对文本的加密解密,还可以实现一套针对内容防伪的数字签名流程。比如,校长在黑板上写下了一段话“明天考试取消,校长留”。大家看到这句话之后如何证明这就是校长写的原话而不是谁的恶作剧?可以这样做:

1.  先计算出这段文本的哈希值。
    哈希算法的具体原理不在此讨论,哈希值可以简单理解为一段文本的“指纹”。完全一样的两段文本的其“指纹”值相同;一段文本的任何改变都会导致“指纹”值的巨大变化,且变化规律不可寻。
2.  再用他的私钥把上述哈希值加密,加密后的值也写到黑板上。
3.  因为校长的公钥是公开的,人人都有,同学看到之后这个留言后,可以拿校长的公钥去解密签名,从而获得一个解密后的哈希值;
    同学们再自己计算一下消息“明天考试取消,校长留”的哈希值。
    如果,这个两个哈希值完全相等,则证明这段话的内容是真的,而且可以确定是校长写的;

如果这两个哈希值不相等,则这则消息一定被篡改过:假设有人篡改了内容,例如改成了“明天考试_不_取消,校长留”,那么这段话的哈希值和解密的哈希值肯定不一样;假设有人伪造签名,那么用校长的公钥解密出来的哈希值肯定和原文的哈希值不一样。如此数字签名流程在非对称机密机制下可以保证一条消息在传输的过程中真实可靠。这里有个细节,“校长留”三个字主动表明了校长的身份,让同学知道用谁的公钥去验证。

验证过程的巧妙设计

一条交易消息的真伪验证过程有两个重要的部分:

1.  要验证交易发起人的身份和交易内容是否相符;
2.  要验证交易发起人对资金来源是否有拥有权;

类似基本的数字签名验证流程,用户X要向全网发起一个交易,他需要对交易消息的内容进行数字签名(用X的私钥sign(hash(交易内容:资金来源的交易ID+转账的数目+接受地址))),并把交易内容和数字签名作为一个整体,一并广播给所有的矿工。这里有个非常巧妙的设计,注意到交易的内容只有:

-   资金来源的交易ID;
-   转账的数目;
-   接收人的公钥(地址);
-   用户X对上述交易内容的数字签名;

对比基本的验证流程,会发现这里并没有类似“校长留”这种主动表面发起人身份的字段,矿工要去哪里找用户X的公钥去验证?还有一个疑问是,如何证明用户X对资金来源的拥有权?比特币在这里的精妙之处是:一个数字签名要能通过验证,能且只能由对应的公钥来进行解密和验证,所以如果一笔交易(交易A)中的的接收人公钥可以对另一笔交易(交易B)的数字签名成功解密并验证通过,意味着:交易A的接收人发起了交易B。因此,如果资金来源交易的收款人公钥可以解密并验证当前付款交易的数字签名,那么这笔交易一定是资金拥有者发起的。验证数字签名的过程既验证了交易发起者的身份,又验证了发起人对资金来源的拥有权。这样的设计还使得节点无需查询或保存交易发起者的任何信息,保证了交易的匿名性。收款地址(公钥)甚至可以离线创建。如果接收人的地址填错了,那这笔钱就永远“丢失了”,因为无法找到一个对应的私钥签名能让下一笔交易通过验证。如果用户把私钥丢了,那所有转到对应地址上的钱款也就都“丢了”。

更进一步,地址

之前的讨论的过程中一直把公钥和地址做等价处理,也提到现有比特币实现中的付款地址是公钥经过一些列哈希变换和编码的结果,实际在交易时收款人填的是收款人的地址,并不是公钥。从公钥到地址的转换程可以描述为:1-计算公钥的SHA256哈希值->2-取上一步结果,计算RIPEMD160哈希值->3-取上一步结果,前面加入地址版本号->4-取上一步结果,计算SHA256哈希值->5-取上一步结果,计算SHA256哈希值->6-取上一步结果的前4个字节加入到步骤4的结果后面->7-取上一步结果,进行base58编码
可以看到地址是公钥的哈希结果,也就是说无法从地址反推到公钥。那上述讨论中交易验证过程时岂不是拿不到公钥?所以现有的比特币实现增加了一个要求:付款人要在交易的时候也需要提供自己的公钥!验证交易的过程中也额外增加一步验证工作:从当前交易发起人提供的公钥推算地址,判断该地址是否和上一笔交易中的收款地址相等。Why?这是多此一举吗?
在目前的技术手段下,公钥是无法反推出私钥的(几乎不可能)。但是谁能保证呢,万一有人穷举出了公钥所对应的私钥(几乎不可能),万一量子计算机被实现了(看上去还很遥远)然后轻易的破解了椭圆加密算法从而可以从公钥推算出私钥呢?私钥暴露等于钱款被盗。因此,在现有的实现中,只暴露了发起者的公钥,收款人的公钥被额外的一层哈希包裹住了,只有当谁要动用这笔钱的时候才会暴露公钥。这让几乎不可能发生的事情又增加了难度,也把可能带来的损失降低了一半。
另外一方面,地址或者公钥都足够复杂,输入的时候“难免”出现错误。要知道比特币一旦转入到一个错误的地址,就几乎等于“丢失”。为了避免这样的惨剧发生,在生成地址第6步的动作引入了校验机制。如果地址输错了(仅指输入错误),那么SHA256(地址去除后四字节)的结果将不等于后四字节。

合并付款,给多人付款和找零。

对于复杂一点的付款流程,比特币也有相应的应对方法。

合并付款

如果用户需要动用两笔以上的收款交易才足够支付一笔付款,那么只要在资金来源里填入所有收款交易的ID就可以了。验证的时候,资金来源的所有交易的收款人公钥都要被拿去验证当前交易的数字签名,全部通过才可以完成交易。

给多人付款

如果用户要给多账户付款,要么只要在收款人栏分别填上所有的“收款地址+金额”的组合。

找零

如果用户使用一笔10 BTC的收款交易去支付一笔只需要付款5 BTC的支付交易,对于多出来的5 BTC该如何处理?比特币规定,在这种情况下,找零的地址和金额需要提前在交易中写好。类似与:

-   收款人:用户Y的公钥,金额:5 BTC;
-   收款人:用户X(自己)的公钥;金额:5BTC;

等于是自己给自己找了5 BTC。这个找零的地址也可以是用户X任意一个公钥地址。
这里是一个复杂交易的样例

弊端

这里仅讨论比特币和区块链在技术层面的缺点。

交易确认慢

比特币网络是一个P2P结构,为了在这个极度复杂的结构下面实现数据一致性,区块打包的速度被人为的限制在10分钟左右,还要对分叉的情况有一定程度的容忍。一般情况下,目前一笔交易要等待6个确认,既一笔交易被打包到一个区块中之后,主链又成功增加了6个区块的长度。这时才几乎可以确认这笔交易得到了全网的确认,大概需要1个小时左右。这确实有些慢。
如果把比特币网络类比成分布式数据库,那么由CAP定理知道这里只能实现CP或AP。因为P(Partition)是必然存在的,必须要在C(Consistence)和A(Availability)之间做取舍。比特币网络首先只允许少数人有数据写入权(发布打包好的区块),其次选择了对一致性的一定容忍。只要你手里有一条区块链,你就可以做交易记录的查询和确认。对大部分的交易,特别是“很久之前”发生的交易这么做毫无问题。但区块的产生速度和分叉情况的存在使得账本上最新的账目并不一致。因此,对“最近”发生的交易,查询结果是不可信的。在这种设计下,要确信交易被正确的记录,等待的成本是必须付出的,这是等待全网获取共识的必要过程。有意思的是,对于历史交易,似乎C、A、P都被满足了。关于区块链和CAP定理,Yaron Goland有一篇专门的Blog讨论The block chain and the CAP Theorem

交易的容量

交易的容量指:在一定时间内,比特币网络所能够处理的交易数。区块的大小是有限制的(See),如果十分钟之类产生的交易过多,一个区块装不下,情况就会比较棘手。选择哪些交易上车,放弃哪些交易?交易如果继续大量拥堵,网络该如何处理也是一件麻烦的事情。现在已经有很多人在讨论改进的方法,但并没有取得实质的共识。

协议的更新

拿上一个问题来说,假设有人设计了一套方法可以解决交易拥堵的问题,但需要对现有的实现和协议进行更新。可是比特币网络是完全自治的,没有一个中心控制器,如何让所有参与者主动接受这些更新,完成软件的升级是个非常困难的事情。这里并不是简单的少数服从多数。假设协议的更新被一部分节点接受,这部分节点从此只接受符合新协议的区块,而另一部分节点只接受符合旧协议的区块。这两部分的人对历史交易都是承认的,但是对新区块的生成和接受却产生了不兼容的分歧,整个区块链就产生了分岔(硬分叉,Hard Fork)。用户该何去何从?这也是众多基于区块链应用需要解决的麻烦之一。
如果区块链应用或协议存在一个漏洞,补救的方法可能并不复杂,补丁怎么同时部署到所有的节点上也是一个问题。

昂贵

大量专业矿机的加入让比特币网络的算计激增,挖矿的难度越来越高,大量的算力被浪费。

隐私

虽然账户信息得到很好的保障,但是交易的信息是全网公开的。这还是存在安全隐患的。

一些概念

去中心化

去中心化作为热点之一一直围绕着区块链应用。但是怎么说,要想清楚,把中心机构拿掉有什么好处,能解决什么问题?
比特币网络解决的数字资产的支付,他所能确保的是“我确实付了一笔钱给另外一个人”。但现实中的交易往往是“一手交钱一手交货”,钱被数字化了,付款的记录得到了全网的认可,那用来做交换的商品呢?比特币是一个完全内部循环的货币系统,没有与现实世界接触的接口。

智能合约

ICO

TODO..

Reference: