区块链基础与应用

本文是对于区块链技术的学习与认识,不定时更新

Posted by gxkyrftx on January 20, 2019

0.前言

本文为区块链的学习笔记,主要参考来源为北京大学肖臻老师《区块链技术与应用》公开课的比特币部分,链接https://www.bilibili.com/video/av37065233/?p=1这门公开课使我获益匪浅,非常感谢老师的讲授!

比特币(BitCoin)的概念最初由中本聪在2009年提出,包括根据中本聪的思路设计发布的开源软件以及建构其上的P2P网络。比特币是一种P2P(Point to Point)形式的数字货币,点对点的传输意味着一个去中心化的支付系统。

1.比特币的密码学原理

比特币是一种加密货币(crypto-currency),它依据特定密码学算法,通过大量的计算产生。比特币中使用了大量的密码学中的知识,例如hash函数,非对称加密体系,签名机制等。以下的文章中将简单介绍这些内容。

1.1 哈希函数(Cryptographic Hash Function)

1.1.1 性质

1.collision resistance:除非使用暴力破解(brute-force),找不到更好的方法制造一个碰撞,
因此这个性质可以应用于数字摘要。但是要说明一点,已知的哈希函数都不能通过数学方法证明其抗碰撞性。
2.hiding:已知x——>h(x),但是由h(x)不能求出x,除了用暴力算法求解x。
应用:与性质1结合,作为digital commitment or digital equivalent of a sealed envelope(将结果作为哈希公布,起到了信封的功能)
3.puzzle friendly(比特币中特有):比特币中挖矿阈值要求:h(block header)<=target,其中block header中的nonce是可变的,就是说,要想通过修改nonce求解出满足target的哈希值,除了一个一个的试nonce,找不到更好的办法来求解,这个性质可以作为挖矿的工作量证明(prove of work)。

1.1.2 SHA-256(Secure Hash Algorithm)

比特币中的哈希函数使用了SHA-256,输出结果为256bit,有关SHA-256算法的详细介绍参考以下链接https://blog.csdn.net/u011583927/article/details/80905740

1.2 签名(Signature)

1.应用了非对称加密算法(Asymmetric Encryption Algorithm),比特币用户只需要创建一对公钥(public key)私钥(private key)对,就可以加入比特币体系。公钥相当于银行账号,私钥相当于密码。

2.使用时用私钥签名,公钥验证签名的合法性。

3.需要一个好的随机源(a good source of randomness)产生公私钥对。

2.比特币的数据结构

2.1 哈希指针(Hash Pointer)

普通c指针指向的是一个地址,哈希指针除了指向一个地址外,还有一个哈希值。要说明的一点时:哈希指针用与无环的结构,环形会形成循环依赖。

2.2 区块链(Block Chain)

一个区块链的结构如下所示

1

它们之间有哈希指针连接,可以实现防篡改日志(tamper-evident log),只需要检测最近产生块(most recent block)的哈希指针,就可以检测出区块内容是否完整,是否被篡改。因此节点可以利用这个性质,只保存几个区块的哈希指针而不用保存所有的信息。

单个区块的结构如下:分为block header(包含区块的宏观信息)和block body(包含实际交易)两个部分

block header block body
version transaction list
hash of previous block header  
merkle root hash  
target  
nonce  

2.3 Merkle tree

2.3.1 Merkle tree简介

相比于数据结构中一般的树,Merkle tree使用了哈希指针,一个典型的Merkle tree如下

2

假如一笔交易发生变动,那么这笔交易的哈希指针会发生变化,该哈希指针的上层哈希指针也会变化,以此类推,从而导致根哈希发生变化,可以很方便的检测交易篡改。

在区块的结构中,block header中包含有Merkle tree的root hash。

2.3.2 Merkle tree作用

提供Merkle prove:轻节点用于确认一笔交易信息是否在区块中。

比特币系统中的节点分为全节点和轻节点,全节点包含了一个区块中交易的所有信息,轻节点只有block header。

3

如果要验证一个交易是否在区块中(如图黄色的transaction),可以通过Merkle prove的方法。由轻节点向全节点发出Merkle prove,全节点提供与这个交易相关的哈希指针(红色的),然后轻节点验证与transaction相关的哈希指针(绿色的),并且将两个指针拼接再次计算哈希,最终可以计算到root H(),轻节点将计算得出的哈希值与本地的哈希值作比较,相等则证明交易在区块中,不等则证明不在。

以上的证明过程是成员资格证明(prove of membership),这种证明过程的复杂度是对数级别的。若要进行非成员资格证明(prove of nonmembership),在Merkle tree未排序的情况下,是线性的;在排好序的Merkle tree中,复杂度是对数级别的。

3.比特币的共识协议

3.1 双花攻击(Double Spending Attack)

数字货币本质上是一串数字,假如仅仅依靠签名来确定数字货币,那么比特币持有者可以通过简单的复制,将这串数字复制多份,然后分别花费。这一节,只在一条链上的讨论这个攻击。

3.2 防范措施

首先举一个例子,交易如下:

1.用户A获得了铸币权(create coin)获得十个比特币这是铸币交易
2.A将十个比特币转给B五个,转给C五个
3.B将五个比特币转给C两个,给D三个
4.C将七个比特币给E七个

4

比特币的每笔交易都包含有输入和输出,输入是指比特币的来源,输出是指比特币转入的账户的公钥的哈希。当B想要将五个比特币给F的时候,回溯到B比特币的来源,会发现B的五个比特币是有交易记录的,已经消费了,因此这笔交易不能完成,成功阻止了double spending attack。

在交易中需要注意的问题:

1.A需要知道B的收款地址,收款地址由B给出。而B需要知道A的公钥以验证A的身份。
2.A的公钥由A给出,其他人不能伪造,因为每笔交易要说明币的来源。
3.交易不需要收款者在线,只是需要将这笔交易记录在区块中。

3.3 共识机制

3.3.1 分布式共识(Distributed Consensus)

比特币系统的各个用户维护一个共同的分布式哈希表(distributed hash table),在表中每一个键值对(key-value pair)都能找到对应。

下面介绍分布式系统中的几个结论

1.FLP impossibility result ,简单的说就是,在异步系统(asynchronous,网络传输时延无上限)中,即使只有一个系统是有问题的(存在faulty),那么这个系统也不会取得共识
2.CAP Theorem:CAP指的是分布式系统的三个性质,C——>consistency,A——>availability,P——>partition tolerance,在一个分布式系统中,如果满足任意两个性质,系统将不会满足第三个性质。

实际中的分布式系统达成共识是可能的,因为理论上不可能的结论是在一个特定的模型下实现的,而现实与理论上是有区别的,我们可以在现实中进行对应用场景进行改造,使系统达成分布式共识。

3.3.2 比特币中的共识协议(Consensus in BitCoin)

3.3.2.1 基于投票的共识协议

假设区块链系统中只有小部分节点是有恶意的,假如此时的投票权由联盟决定,这种方案是可行的。 存在的问题:女巫攻击(sybil attack),在比特币系统中,恶意节点产生大量的用户账号,当账号数量超过一半时,就可以操纵投票结果。

3.3.2.2 基于算力投票的共识协议

每个节点将合法交易在本地组装为一个区块,通过改变nonce的值,不断穷举符合条件的哈希值,然后放入Block Header,获得记账权,检查交易的合法性,最后组装成一个区块发布。

这个协议通过节点解puzzle的能力大小决定了投票的权重。

3.3.2.3 最长合法链

区块链中的链的扩展应该遵循最长合法链原则,即扩展当前位置的最长的那条链。假如两个区块同时发布,链的长度相同,则节点会接收先收到的区块,然后继续计算,直到最长合法链的再次出现,另一个区块会被放弃成为丢弃块(orphan block)

3.3.2.4 出块奖励

当节点通过不断尝试nonce计算出满足条件的hash值时,该节点获得记账权随后可以产生一定数量的新的比特币(也就是coinbase transaction),也就是出块奖励(block reward)。

出块奖励的计算

初始为50BTC,每隔210000个比特币减半。

3.3.2.5 交易费

获得记账权的节点,将一笔交易记录打包进入区块后,可以获得一笔交易费(transaction fee)。

4.比特币的实现

4.1 比特币的实例

来源于https://www.blockchain.com/zh/btc/block/0000000000000000002c185e0e8e1c6aa99ed260eab542a582bb1b82021383d7

5

比特币出现时,由于算力较低,如果要达到平均10分钟出一个块的要求,则要将target域变大,使puzzle难度低。矿工只需要穷举nonce就可以找到满足target的值。随着算力的增加,10分钟出一个块的要求不变,因此需要使puzzle难度变大,此时只靠改变nonce有可能找不到满足target域的解,因此需要通过改变同时Merkle Root(64bit)与nonce(32bit),形成二重循环来寻找解。具体的做法跟coinbase transaction域中的内容有关,先看下图

6

比特币的每笔交易包含着输入和输出,但是铸币交易(coinbase transaction)是产生比特币的源头,没有输入,而是获得记账权的节点向其中写入一段信息作为输入。矿工可以通过不断地修改coinbae transaction中的内容,从而改变这笔交易的hash,依次向上改变Merkle Root Hash。

4.2 挖矿的概率分析

每次挖矿相当于是伯努利实验(Bernoulli trial),当进行了很多的伯努利试验后,这些实验就构成了伯努利分布(Bernoulli process),具有无记忆性,就是前面的实验结果对后面的实验没有影响。

对于挖矿来说,伯努利分布可以由泊松分布(Poisson Process)来近似,出块时间可推导出符合指数分布(Exponential Distribution),指数分布也是具有无记忆性的,具体来说就是出块时间跟已经花费的计算时间没有关系,已经计算了十分钟没有出块,并不意味着在今后很短的一段时间内会出块。

假如,挖矿过程中的puzzle是有记忆的,这样对算力弱的矿工是不公平的。算力强的矿工可以计算出很多次,可以有更多的准备,相比于算力弱的矿工获得了与算力不成比例的优势。

4.3 比特币的数量

几何级数,每隔21万个区块,比特币减半,总量为

210000*50*(1+1/2+1/4+1/8+....)=21000000

4.4 分叉攻击(Forking Attack)

4.4.1 分叉攻击例一

7

如图所示,A转账给M,这笔交易写入区块后,A想回滚这笔交易,将比特币转给自己,并且重新打包了一个区块。假如没有后续的6个确认区块,那么这样是完全可行的。所以在交易过程中,为了避免这样的分叉攻击,可以等6个确认区块后再确认。

4.4.2 分叉攻击例二

4.4.2.1 selfish mining

如下图

8

A转账给M,黄色的区块为攻击者A事先计算好的,但是未发布的区块,等到M发现有6个确认区块后,完成交易,A立刻发布自己制造的区块,将比特币转给自己,使其成为最长合法链,然后按照这条链继续扩展,上面的链被丢弃,达到了目的。

这种攻击方式在现实中不可行,因为诚实的节点是大多数的,算力也被掌握在大多数节点手中,这种做法,在计算上不可行。

4.4.2.2 selfish mining的优势与风险

如下图

9

攻击者A由于算力足够大,在某个位置先于其他节点挖出了一个区块A1,但是它不发布这个区块,而是继续沿着A1计算A2,而此时其他节点正在计算区块其他1,这样做分散了算力,使A能够有更多的机会计算出A2。如果计算出A1后立即将A1发布,会使其他算力也向A1聚集,对A不利。

风险:A在计算A2时,区块其他1被计算出,由于A1未发布,其他链成为最长合法链,算力会聚集于这条链,更容易计算出其他2。归根到底,还是算力的竞争。

4.5 基于账本的交易模式(transaction-based ledger)

用户无法直接知道一个账号有多少比特币,只能通过一笔一笔的交易计算。比特币系统中的全节点维护了UTXO(Unspent Transaction Output)集合,也就是未消费的交易输出的集合,它的作用是检测double spending attack之类的攻击。

4.6 基于账户的模式(account-based ledger)

显式记录账户金额,方便查询

5.比特币网络的工作原理

5.1 比特币网络结构

结构 协议
application layer BitCoin Block Chian
network layer P2P Overlay Network

比特币网络中的节点是完全对等的,不像传统的p2p中有master node

5.2 比特币网络中的节点

全节点 轻节点
数量少 数量多
一直在线 需要的时候在线
在本地硬盘上维护完整的区块链信息 只保存区块块头
在内存中维护UTXO集合,可快速检验交易的正确性 只保存与自身相关的交易
监听比特币网络上的交易信息,验证每个交易的合法性 只验证与自身相关的交易的合法性
决定哪些交易会被打包到区块中  
监听其他矿工挖出的区块是否合法 无法验证区块是否合法
决定挖矿的方向 验证挖矿难度,检测最长链,而不是最长合法链

5.3 比特币网络设计原则

简单(simple),鲁棒(robust),而不是高效。

比特币网络中,交易消息的传播使用洪泛(flooding),牺牲了高效性,交易传播时不考虑下层的拓扑结构;区块的传播也使用了相同的方式,并且检测该区块是否处于最长合法链。

best effort:当一笔交易发布到比特币网络上时,不同节点收到的交易的顺序和能否收到交易时不确定的。

6.比特币的挖矿难度

6.1 挖矿难度(Difficulty)

挖矿难度的改变就是通过调整target值实现的,他们之间成反比。difficulty=difficulty_1_target/target.

调整挖矿难度是因为算力的增加,使区块的产生时间不是10分钟,而是小于10分钟。如果区块的产生时间过短,由于区块在比特币网络上传播有时延,各个节点不能统一信息,就会出现分叉,如下图。

10

此时恶意节点会通过集中算力,扩展自己的黑色链,发动51%攻击,此时的算力已经不需要51%了,因为其他的非恶意节点的算力被分散到了很多链中,当他们的算力没有恶意节点大时,由于恶意节点扩展了最长合法链,会使其他节点到最后也跟着恶意节点计算。

6.2 调整公式

规定,每隔2016个区块调整一次挖矿难度。也就是每隔:2016x10/(60x24)=14天,调整一次。

目标阈值调整公式

target=target*(actual time/expected time)=target*(time spent mining the last 2016 blocks/2 weeks)

挖矿难度调整公式

next_difficulty=previous_difficulty*(2 weeks/time to mine last 2016 blocks)

对这个公式的一些解释

1.实际产生2016个区块的时间大于预期时(14天),由公式得,阈值相比于之前会增大,挖矿难度降低
2.阈值变化有上下限,最高增大4倍,最低降为原来的1/4.
3.阈值调整是所有节点都应该进行的,假如有节点为降低挖矿难度增大阈值,降低挖矿难度,该节点计算出的hash是不被其他节点认可的。

7.挖矿

7.1 挖矿设备专业化

挖矿所用的设施变化:CPU——>GPU——>ASIC(Application Specific Integrated Circuit)

从通用计算到通用并行计算(深度学习再到挖矿专用

ASIC芯片专门设计用于某一种货币的挖矿,解决一个特定的mining puzzle,当新的ASIC芯片生产出之后,整个比特币市场的算力会有一个大幅度的提高,各个矿工会争相购买新的矿机进行挖矿以获取更高的利润。随后整体算力会增加,挖矿难度加大,促使下一代ASIC芯片出现。
可以通过Alternative puzzle实现ASIC resistance,使得CPU,GPU用户都可以参与,而不是使挖矿收益都被大厂的ASIC矿机垄断。

7.2 矿池出现

7.2.1 矿池(Mining Pool)

将矿工组织成矿池,用一个全节点驱动整个矿池运作。矿池一般结构如下图:

11

这种做法的优势在于

1.每个矿工不需要维护负责的全节点,只需进行哈希计算。
2.收入稳定,单个矿工的挖矿类似于买彩票,矿池挖矿有利于收益的稳定。

当前时间段矿池份额如下:

12

信息来源https://btc.com/stats/pool?pool_mode=day3

7.2.2 矿池的组织形式

集中式:所有的矿工经过pool manager的组织形成了一个类似公司的形式。

分布式:矿工来自世界各地,分别属于不同的组织或者无组织,仅仅参与挖矿。

7.2.3 矿池的收益分配

对于集中式,分配内部自行协商。

对于分布式,采取工作量证明,具体如下: 矿主要求矿工提交挖矿难度较小的一些区块,称为share也叫almost valid block。矿工将这些share提交给矿主作为工作量证明,矿主将这些share保存,等到某一时刻,有矿工提交了符合目标阈值的block,矿主获得比特币,再将比特币按各个矿工提交的share的数目进行分配。

安全性:矿工不可能偷到出块奖励。因为假如矿工将符合目标阈值的区块不交给矿主而是自己发布,矿工也拿不到记账权,因为矿工只负责计算哈希值,而块头信息中包含的是矿主的信息,即使该矿工发布了区块,最后获得收益的也是矿主。

7.2.4 矿池的安全性

矿池如果拥有51%的算力,可以发动51%攻击(51%不是绝对的,是一个概率值,每个矿池的算力也是动态变化的估计值)。

最常见的是分叉攻击,前面有介绍。

其次还有Boycott,如下图所示:

13

A想将自己的交易记录写入区块,但是此时某个矿池拥有51%的算力,它立即制造出两个合法的黑色区块,使自己的链成为最长合法链,使算力向这条链集中,包含A交易的区块变成了orphan block,等到A想将自己的交易写入区块时,矿池继续产生最长合法链,最终达到抵制A的目的。

8.比特币交易中使用的脚本形式

一笔交易如下,来源:https://www.blockchain.com/zh/btc/tx/8fd689688845f0c0eb194b2afa57d6c548153d10d7f7eaf9e87543b35a74692b

14

我们可以从图中看到一些有关交易的信息。下面是这笔交易的输入与输出脚本。

15

验证交易是否合法,需要将输入输出脚本分别验证,看脚本能否成功执行。如下图所示:

21

当B想要给C比特币时,需要将这笔交易的输入脚本执行,然后再将A——>B的输出脚本执行,最后根据结果判断是否是合法交易。

8.1 P2PK(Pay to Public Key)

input script
    PUSHDATA(Sig)
output script:
    PUSHDATA(Pubkey)     //收款人公钥
    
    CHECKSIG

执行过程为先将签名压入栈,然后将公钥压入栈,随后公钥检验签名的正确性,栈变化如下图所示。

——> ——>
  ——> pubkey ——>  
sig ——> sig ——> true

8.2 P2PKH(Pay to Public Key Hash)

input script:
    PUSHDATA(Sig)
    PUSHDATA(PubKey)
output script:
    DUP
    HASH160
    PUSHDATA(PubKeyHash)
    EQUALVERIFY
    CHECKSIG

执行过程为签名入栈,公钥入栈。然后将入栈的公钥复制,并且计算哈希160值,放入栈中,然后将由收款方给出的PubKeyHash入栈,比较两个值是否相等,相等则返回true。

栈变化图如下:

——> ——> ——> ——> ——>
  ——>   ——>   ——> pubkeyhash ——>   ——>  
  ——>   ——> pubkey ——> pubkeyhash ——>   ——>  
  ——> pubkey ——> pubkey ——> pubkey ——> pubkey ——>  
sig ——> sig ——> sig ——> sig ——> sig ——> true

这种方式最常见,如下图所示:

23

账户地址https://www.blockchain.com/zh/btc/address/1x6YnuBVeeE65dQRZztRWgUPwyBjHCA5g

输入脚本所在的交易 https://www.blockchain.com/zh/btc/tx/51680099227e499ec194662e24c51a8d709fb8a87e40c45ac0c95130cc0b223e

输出脚本所在的交易 https://www.blockchain.com/zh/btc/tx/11836ab2f759bf4ee74823d11e5d438cbf2456879934cb4a990f736cea300840

8.3 P2SH(Pay to Script Hash)

input script:
    
    PUSHDATA(Sig)
    
    PUSHDATA(serialized redeemScript)
output script:
    HASH160
    PUSHDATA(redeemScriptHash)
    EQUAL

P2SH在最初的协议设计时是不存在的,后来通过软分叉的方式加入。

在P2SH中,input script要给出一些签名(数目不定)及一段序列化的redeemScript

验证时分两步:第一步验证这段序列化的redeemScript是否与output script中的哈希值匹配?第二步反序列化并执行redeemScript ,配合前边的签名是否可以执行通过。

redeemScriptHash是赎回脚本,可以设计成多种形式,比如前面的P2PK或者P2PKH形式,以及多重签名形式。

用P2SH实现P2PK的实例为

redeemScript
    PUSHDATA(PubKey)
    CHECKSIG
input script:
    PUSHDATA(Sig)
    PUSHDATA(serialized redeemScript)
output script:
    HASH160
    PUSHDATA(redeemScriptHash)
    EQUAL

执行过程为,签名入栈,序列化的redeemScript入栈,然后计算哈希160,随后输出脚本中的redeemScriptHash入栈,比较两者是否相等,相等则同时出栈,然后执行赎回脚本,公钥入栈,检查是否与签名对应,若对应返回true。栈变化如下:

—> —> —> —> —> —>
  —>   —>   —> RSH —>   —>   —>  
  —> serialRS —> RSH —> RSH —>   —> pubkey —>  
sig —> sig —> sig —> sig —> sig —> sig —> true

这种方式的应用,如下图所示

24

8.4 多重签名

多重签名是指多个用户对同一个文件进行签名和认证,增强了安全性,防止个人的破坏,同时增加了容错性。多重签名具体实现的输入输出脚本:

input script:
    x                               //协议设计时的bug,需要添加一个没用的元素
    
    PUSHDATA(Sig_1)
    PUSHDATA(Sig_2)
    ...
    PUSHDATA(Sig_M)
outputScript
    M                               //M个签名,满足数量后,可参与验证
    
    PUSHDATA(pubkey_1)
    PUSHDATA(pubkey_2)
    ...
    PUSHDATA(pubkey_N)
    N                               //N个公钥,事先存储
    
    CHECKMULTISIG

一个实例脚本如下:

input script:
    FALSE                               
    PUSHDATA(Sig_1)
    PUSHDATA(Sig_2)
outputScript
    2                               
    PUSHDATA(pubkey_1)
    PUSHDATA(pubkey_2)
    PUSHDATA(pubkey_3)
    3                               
    CHECKMULTISIG

执行过程如下所示:首先输入脚本将FALSE入栈,然后两个签名入栈。输出脚本中参数2入栈,三个公钥入栈,用来检查签名的合法性,然后参数3入栈,随后检查多重签名,满足条件即可通过。

—> —> —> —> —>  
  —>   —>   —>   —> 3 —>    
  —>   —>   —> pubkey_3 —> pubkey_3 —>    
  —>   —>   —> pubkey_2 —> pubkey_2 —>    
  —>   —>   —> pubkey_1 —> pubkey_1 —>    
  —>   —> 2 —> 2 —> 2 —>    
  —> Sig_2 —> Sig_2 —> Sig_2 —> Sig_2 —>    
  —> Sig_1 —> Sig_1 —> Sig_1 —> Sig_1 —>    
FALSE —> FALSE —> FALSE —> FALSE —> FALSE —> TRUE  

这种多重签名的问题主要在于,将提供参数,提供给公钥的行为交与用户,不利于用户体验。因此产生了P2SH实现多重签名。

8.5 用P2SH实现多重签名

这种方式将复杂度从输出脚本转移到了输入脚本的redeemScript,将用户的工作降到最低。

RedeemScript
    M
    PUSHDATA(pubkey_1)
    PUSHDATA(pubkey_2)
    ...
    PUSHDATA(pubkey_N)
    N
    CHECKMULTISIG
input script:
    x
    PUSHDATA(Sig_1)
    PUSHDATA(Sig_2)
    ...
    PUSHDATA(Sig_M)
    PUSHDATA(Serialized RedeemScript)
output script:
    HASH160
    PUSHDATA(RedeemScriptHash)
    EQUAL

一个实例脚本如下:

RedeemScript
    2
    PUSHDATA(pubkey_1)
    PUSHDATA(pubkey_2)
    PUSHDATA(pubkey_3)
    3
    CHECKMULTISIG
input script:
    FALSE
    PUSHDATA(Sig_1)
    PUSHDATA(Sig_2)
    PUSHDATA(Serialized RedeemScript)
output script:
    HASH160
    PUSHDATA(RedeemScriptHash)
    EQUAL

执行过程如下:输入脚本中的内容全部进栈,然后将Serialized RedeemScript计算hash160,将输出脚本中的RedeemScriptHash入栈,将两者作比较,若相等则执行RedeemScript,将RedeemScript的内容全部入栈,然后检查,满足条件则为true。

—> —> —> —> —>  
  —>   —>   —>   —> 3 —>    
  —>   —>   —>   —> pubkey_3 —>    
  —>   —>   —>   —> pubkey_2 —>    
  —>   —> RSH —>   —> pubkey_1 —>    
SeriRS —> RSH —> RSH —>   —> 2 —>    
Sig_2 —> Sig_2 —> Sig_2 —> Sig_2 —> Sig_2 —>    
Sig_1 —> Sig_1 —> Sig_1 —> Sig_1 —> Sig_1 —>    
FALSE —> FALSE —> FALSE —> FALSE —> FALSE —> TRUE  

8.6 烧毁证明(Proof of Burn)

只存在于输出脚本,在这个脚本中无论return后为何值,都会返回false,包含了这样的output script的output被称为Provably Unspendable/Prunable Outputs。脚本格式为:

output script:
    RETURN
    [zero or more ops or text]

这个脚本是证明销毁比特币的方法,应用场景主要有以下两种形式:

1.小币种要求销毁一定数量的比特币才可以得到该币种
2.往区块链中写入一些内容,可以把这些信息直接固定在区块链上,无法篡改。这个作用类似于每个区块中的coinbase域,Proof of Burn与之不同的一点在于任何节点,任何用户都可以使用。而往coinbase域写入信息是获得记账权的节点特有的属性。

如下图所示,Unable to decode output address - (Unspent) 部分就包含了Prunable Outputs,也就是该用户向区块链中写入了一些信息。

22

销毁比特币后,不用将其放到UTXO集合,节省了空间,对于矿工是很友好的。

9.区块链分叉

9.1 状态分叉(State Fork)

由于对区块链当前状态的判断不同产生的分叉,例如,同时产生两个合法区块,节点在先收到的区块后进行扩展,由于区块在网络上的传播有时延,各个节点可能接受两个中任何一个区块,造成state fork。state fork的一个实例就是分叉攻击。

9.2 协议分叉(Protocol Fork)

由于协议版本不同,或者具体实现的时候有差异产生的分叉成为protocol fork,protocol fork分为hard fork和soft fork。

9.2.1 硬分叉(Hard Fork)

硬分叉是对比特币协议进行扩展或者修改,增加一些新的特性,更新协议的节点与未更新协议的节点之间会产生不一致,未更新的节点拒绝验证已经更新的节点产生的块,造成硬分叉,这是一种长期的分叉。

其中的一个例子就是对区块大小限制的修改,假如对比特币协议进行修改,使区块大小限制由1M——>4M。如下图所示:

16

此时比特币系统中拥有绝大多数算力的用户更新了协议,而剩下的一部分用户未更新。会出现的问题:

1.新协议挖出的块,不被旧协议认可,因为其中包含的交易有他认为不合法的。
2.大部分算力集中于新协议,扩展速度快;而少部分算力由于不认可新协议,也在扩展自己的链,造成链的分叉,这是一种长期的分叉。

硬分叉会形成多种加密货币,分叉出的加密货币都是被认可的。

实际的例子:早期的ETH收到黑客攻击后,形成ETH和ETC,ETH是旧链。

硬分叉会带来的问题:账户金额同时存在于两条链,会存在重放攻击。如下图:

17

M是一个恶意用户,B收到A的一笔比特币,然后转在新的加密货币上给M,M把这笔交易在旧的加密货币上重放,结果M收到了两笔加密货币的交易。同样的B也可以进行类似的重放。为了防止这样的问题的出现,需要设置chain id,来确认是哪一条链的加密货币。

9.2.2 软分叉(Soft Fork)

软分叉是指区块链网络系统版本或者协议进行升级之后,旧的区块并不知道比特币网络以及升级了,并且继续接受由新节点创造的区块,新老节点还是在同一条链上工作。

举例说明就是对区块大小限制的修改,假如对比特币协议进行修改,使区块大小限制由1M——>0.5M。如下图所示:

18

由于大部分节点升级了协议,算力集中于新协议,能够很快的产生最长合法链,而少部分区块未升级协议,依旧按原来的方案挖矿,由于旧的协议接受新的区块,而新协议的链更容易形成最长合法链,旧协议区块会转向新协议。但是它后来挖出的区块,不被新协议接受,只是在做无用功,拿不到出块奖励。

实际例子:P2SH,软分叉加进去的

10.比特币的匿名性(anonymity)

匿名性通常与隐私保护联系。

10.1 匿名性遭到破坏

10.1.1 多个账户关联

在一笔交易中,如下图所示:

19

输入方的付款地址可能不止一个,这时就可以判断两个地址是关联的,有极大的可能性两个地址是同一个用户。除此之外,输出部分的地址也可能不止有收款方的地址,也可能存在有付款方的地址。

10.1.2 与现实世界联系

通过现实中的货币购买比特币,通过现实世界中的资金的转入链转出链,判断比特币与实体的关联情况。通过比特币购买商品,可以留下记录。

10.2 匿名性的增强方法

10.2.1 网络层匿名

网络层匿名研究已经较成熟,可以通过多路径路由的方式(应用实例:Tor),多跳转发,每个中间节点只知道自己的上一个节点,不知道源地址是什么。只要有一个节点按照这种方式转发,那么源地址就可以被隐藏。

10.2.2 应用层匿名

1.coin mixing的功能:部分服务商提供这样的服务,用户将自己的比特币放进去,换回来的是其他用户的比特币,金额相同但是地址变了。这样做的问题在于,服务商缺乏监管,容易造成风险。

2.比特币钱包软件:有些软件提供了类似于coin mixing的功能。

3.交易所交易:不同币种,不同用户的交易,可以间接提供coin mixing的功能。

10.3 零知识证明( Zero-knowledge Proofs)

零知识证明是指一方(证明者)向另一方(验证者)证明一个陈述是正确的,而无需透露除该陈述是正确的外的任何信息。加密数字货币与区块链为零知识证明的应用提供了新的方向。一个典型的零知识证明如下:

举例:A 要向 B 证明自己拥有某个房间的钥匙,假设该房间只能用钥匙打开锁,而其他任何方法都打不开。有两个方法:
1.A 把钥匙出示给 B,B 用这把钥匙打开该房间的锁,从而证明 A 拥有该房间的正确的钥匙。
2.B 确定该房间内有某一物体,A 用自己拥有的钥匙打开该房间的门,然后把物体拿出来出示给 B,从而证明自己确实拥有该房间的钥匙。 后面的方法 2 属于零知识证明。好处在于在整个证明的过程中,B 始终不能看到钥匙的样子,从而避免了钥匙的泄露。

Zcash是零知识证明在加密数字货币与区块链中的应用,官网链接https://z.cash/

Zcash 是分布式状态和个人用户所拥有的资产证明的结合体,其终极匿名特性也归功于零知识证明,通过名为 zk-SNARK https://z.cash/technology/zksnarks/ 的技术验证交易的真实性,利用一个公共区块链来展示交易,但会隐藏掉交易的金额,而查看密钥的所有者,即币的拥有者,可允许他人查看这个密钥相关联的信息。

10.4 同态隐藏(Homomorphic Hiding)

一个满足同态隐藏的函数有下面的几点属性:

1. For most x’s, given E(x) it is hard to find x.(单向性)
2. Different inputs lead to different outputs – so if x≠y,then E(x)≠E(y).(无碰撞,哈希函数是有碰撞的,找到碰撞在计算上不可行)
3. If someone knows E(x)and E(y),they can generate the HH of arithmetic expressions in x and y. For example, they can compute E(x+y) from E(x) and E(y).(同态运算)

同态运算举例如下:

Alice想要向Bob证明她知道一组数𝑥和𝑦使得𝑥 + 𝑦 = 7,同时不让Bob知道𝑥和𝑦的具体数值。 解决方法如下图

20

此外,在这个例子中,可以通过随机化的方法对x,y进行处理,使处理后的x’+y’=x+y提高安全性,防止Bob对x和y的穷举攻击。

10.5 盲签方法

前面提到了防范双花攻击的一种方法是对比特币进行编号,产生比特币与用户对应的键值对,防止攻击。而为了保证去中心化的这个要求,编号不能由中心化机构产生,应该由用户产生,如何验证用户的序号?采用盲签方法,具体实现如下

1.用户A提供SerialNum,银行在不知道SerialNum的情况下返回签名Token,减少A的存款
2.用户A把SerialNum和Token交给B完成交易
3.用户B拿SerialNum和Token给银行验证,银行验证通过,增加B的存款
4.银行无法把A和B联系起来

11.Q&A

11.1 转账交易收款方不在线

收款方不需要在线,比特币交易只需要将这笔交易写入区块,就可以证明收款方收到了转账

11.2 比特币账户可能是从未出现过的

这是可能的,因为创建一个账户只需要一个公钥和私钥,只要不发生交易,那么这个账户就有可能从来没有在这个网络上出现。

11.3 私钥丢失后

没有办法,成为死钱,无法找回。加密货币交易所存储私钥的安全性并不比个人存储高,因为缺乏监管,安全性不高。

11.4 私钥泄露后

尽快将比特币转到另一个自己的账号。

11.5 转账地址写错

没有办法补救,地址有很大可能性不存在。

11.6 矿工偷比特币

不可能存在,因为找到的hash值是由coinbase transaction中的节点的收款地址绑定的,如果恶意节点将收款地址修改,那么Merkel tree的根哈希值会变,从而导致计算出的哈希值变化。

11.7 交易费给哪个矿工

不需要提前指定交易费,因为如果矿工获得记账权,他会知道一笔交易的total input和total output,打包的时候,就会用total input-total output得到交易费。

<终>


本文访问量: