根生群算法
Ⅰ 共识算法系列之一:私链的raft算法和联盟链的 pbft 算法
对数据顺序达成一致共识是很多共识算法要解决的本质问题
Fabic的pbft算法实现
现阶段的共识算法主要可以分成三大类:公链,联盟链和私链
私链,所有节点可信
联盟链,存在对等的不信任节点
私链:私链的共识算法即区块链这个概念还没普及时的传统分布式系统里的共识算法,比如 zookeeper 的 zab 协议,就是类 paxos 算法的一种。私链的适用环境一般是不考虑集群中存在作恶节点,只考虑因为系统或者网络原因导致的故障节点。
联盟链:联盟链中,经典的代表项目是 Hyperledger 组织下的 Fabric 项目, Fabric0.6 版本使用的就是 pbft 算法。联盟链的适用环境除了需要考虑集群中存在故障节点,还需要考虑集群中存在作恶节点。对于联盟链,每个新加入的节点都是需要验证和审核的。
公链:公链不仅需要考虑网络中存在故障节点,还需要考虑作恶节点,这一点和联盟链是类似的。和联盟链最大的区别就是,公链中的节点可以很自由的加入或者退出,不需要严格的验证和审核。
在公有链中用的最多的是pow算法和pos算法,这些算法都是参与者的利益直接相关,通过利益来制约节点诚实的工作,解决分布式系统中的拜占庭问题。拜占庭容错算法是一种状态机副本复制算法,通过节点间的多轮消息传递,网络内的所有诚实节点就可以达成一致的共识。
使用拜占庭容错算法不需要发行加密货币,但是只能用于私有链或者联盟链,需要对节点的加入进行权限控制;不能用于公有链,因为公有链中所有节点都可以随意加入退出,无法抵挡女巫攻击(sybil attack)
raft 算法包含三种角色,分别是:跟随者( follower ),候选人(candidate )和领导者( leader )。集群中的一个节点在某一时刻只能是这三种状态的其中一种,这三种角色是可以随着时间和条件的变化而互相转换的。
raft 算法主要有两个过程:一个过程是领导者选举,另一个过程是日志复制,其中日志复制过程会分记录日志和提交数据两个阶段。raft 算法支持最大的容错故障节点是(N-1)/2,其中 N 为 集群中总的节点数量。
国外有一个动画介绍raft算法介绍的很透彻,链接地址为: http://thesecretlivesofdata.com/raft/ 。这个动画主要包含三部分内容,第一部分介绍简单版的领导者选举和日志复制的过程,第二部分内容介绍详细版的领导者选举和日志复制的过程,第三部分内容介绍的是如果遇到网络分区(脑裂),raft 算法是如何恢复网络一致的。
pbft 算法的提出主要是为了解决拜占庭将军问题
要让这个问题有解,有一个 十分重要的前提 ,那就是 信道必须是可靠的 。如果信道不能保证可靠,那么拜占庭问题无解。关于信道可靠问题,会引出两军问题。两军问题的结论是,在一个不可靠的通信链路上试图通过通信以达成一致是基本不可能或者十分困难的。
拜占庭将军问题最早是由 Leslie Lamport 与另外两人在 1982 年发表的论文《The Byzantine Generals Problem 》提出的, 他证明了在将军总数大于 3f ,背叛者为f 或者更少时,忠诚的将军可以达成命令上的一致,即 3f+1<=n 。算法复杂度为 o(n^(f+1)) 。而 Miguel Castro (卡斯特罗)和 Barbara Liskov (利斯科夫)在1999年发表的论文《 Practical Byzantine Fault Tolerance 》中首次提出 pbft 算法,该算法容错数量也满足 3f+1<=n ,算法复杂度为 o(n^2)。
首先我们先来思考一个问题,为什么 pbft 算法的最大容错节点数量是(n-1)/3,而 raft 算法的最大容错节点数量是(n-1)/2 ?
对于raft算法,raft算法的的容错只支持容错故障节点,不支持容错作恶节点。什么是故障节点呢?就是节点因为系统繁忙、宕机或者网络问题等其它异常情况导致的无响应,出现这种情况的节点就是故障节点。那什么是作恶节点呢?作恶节点除了可以故意对集群的其它节点的请求无响应之外,还可以故意发送错误的数据,或者给不同的其它节点发送不同的数据,使整个集群的节点最终无法达成共识,这种节点就是作恶节点。
raft 算法只支持容错故障节点,假设集群总节点数为n,故障节点为 f ,根据小数服从多数的原则,集群里正常节点只需要比 f 个节点再多一个节点,即 f+1 个节点,正确节点的数量就会比故障节点数量多,那么集群就能达成共识。因此 raft 算法支持的最大容错节点数量是(n-1)/2。
对于 pbft 算法,因为 pbft 算法的除了需要支持容错故障节点之外,还需要支持容错作恶节点。假设集群节点数为 N,有问题的节点为 f。有问题的节点中,可以既是故障节点,也可以是作恶节点,或者只是故障节点或者只是作恶节点。那么会产生以下两种极端情况:
第一种情况,f 个有问题节点既是故障节点,又是作恶节点,那么根据小数服从多数的原则,集群里正常节点只需要比f个节点再多一个节点,即 f+1 个节点,确节点的数量就会比故障节点数量多,那么集群就能达成共识。也就是说这种情况支持的最大容错节点数量是 (n-1)/2。
第二种情况,故障节点和作恶节点都是不同的节点。那么就会有 f 个问题节点和 f 个故障节点,当发现节点是问题节点后,会被集群排除在外,剩下 f 个故障节点,那么根据小数服从多数的原则,集群里正常节点只需要比f个节点再多一个节点,即 f+1 个节点,确节点的数量就会比故障节点数量多,那么集群就能达成共识。所以,所有类型的节点数量加起来就是 f+1 个正确节点,f个故障节点和f个问题节点,即 3f+1=n。
结合上述两种情况,因此 pbft 算法支持的最大容错节点数量是(n-1)/3
pbft 算法的基本流程主要有以下四步:
客户端发送请求给主节点
主节点广播请求给其它节点,节点执行 pbft 算法的三阶段共识流程。
节点处理完三阶段流程后,返回消息给客户端。
客户端收到来自 f+1 个节点的相同消息后,代表共识已经正确完成。
为什么收到 f+1 个节点的相同消息后就代表共识已经正确完成?从上一小节的推导里可知,无论是最好的情况还是最坏的情况,如果客户端收到 f+1 个节点的相同消息,那么就代表有足够多的正确节点已全部达成共识并处理完毕了。
3.算法核心三阶段流程
算法的核心三个阶段分别是 pre-prepare 阶段(预准备阶段),prepare 阶段(准备阶段), commit 阶段(提交阶段)
流程的对比上,对于 leader 选举这块, raft 算法本质是谁快谁当选,而 pbft 算法是按编号依次轮流做主节点。对于共识过程和重选 leader 机制这块,为了更形象的描述这两个算法,接下来会把 raft 和 pbft 的共识过程比喻成一个团队是如何执行命令的过程,从这个角度去理解 raft 算法和 pbft 的区别。
一个团队一定会有一个老大和普通成员。对于 raft 算法,共识过程就是:只要老大还没挂,老大说什么,我们(团队普通成员)就做什么,坚决执行。那什么时候重新老大呢?只有当老大挂了才重选老大,不然生是老大的人,死是老大的鬼。
对于 pbft 算法,共识过程就是:老大向我发送命令时,当我认为老大的命令是有问题时,我会拒绝执行。就算我认为老大的命令是对的,我还会问下团队的其它成员老大的命令是否是对的,只有大多数人 (2f+1) 都认为老大的命令是对的时候,我才会去执行命令。那什么时候重选老大呢?老大挂了当然要重选,如果大多数人都认为老大不称职或者有问题时,我们也会重新选择老大。
四、结语
raft 算法和 pbft 算法是私链和联盟链中经典的共识算法,本文主要介绍了 raft 和 pbft 算法的流程和区别。 raft 和 pbft 算法有两点根本区别:
raft 算法从节点不会拒绝主节点的请求,而 pbft 算法从节点在某些情况下会拒绝主节点的请求 ;
raft 算法只能容错故障节点,并且最大容错节点数为 (n-1)/2 ,而 pbft 算法能容错故障节点和作恶节点,最大容错节点数为 (n-1)/3 。
pbft算法是通过投票来达成共识,可以很好的解决包括分叉等问题的同时提升效率。但仅仅比较适合于联盟链私有链,因为两两节点之间通信量是O(n^2)(通过优化可以减少通信量),一般来说不能应用于超过100个节点。
pbft有解的前提是 信道必须是可靠的 ,存在的问题是 可扩展性(scalability)差
部分来自: https://blog.csdn.net/kojhliang/article/details/80270223
区块链在设计上就是为了BFT
Ⅱ 密码学系统
本文分为7个部分,第1部分介绍密码学的基本概念,第2部分讲解常见的对称加密算法,第3部分讲解常见的非对称加密算法,第4部分讲解 数字签名, 第5部分讲解PKI(Public Key Infrastructure),第6部分讲解哈希函数加密,第7部分讲解密码学在区块链里的应用, 最后一部分会讲解随机数。
比较常见的对称加密算法有: Digital Encryption Standard(DES), Triple-DES, IDEA, BLOWFISH。
对称加密的挑战:
非对称加密的挑战:
比较常见的非对称加密算法有: RSA, ElGamal, ECC。
菲斯特尔结构的块加密算法是着名的一个分组密码加密的设计模型。
1990年后对DES进行彻底的密钥搜索的速度开始引起DES用户的不适。 然而,用户并不想取代DES,因为它需要花费大量的时间和金钱来改变广泛采用并嵌入到大型安全架构中的加密算法。
务实的做法不是完全放弃DES,而是改变DES的使用方式。 这导致了三重DES(3DES)的修改方案。
三重DES
在使用3TDES之前,用户首先生成并分配一个3TDES密钥K,它由三个不同的DES密钥K1,K2和K3组成。
详细可以看 Triple-DES
高级加密标准(Advanced Encryption Standard,AES)是目前比较流行和广颂桥扮泛采用的对称加密算法。 发现至少比三重DES快6倍。
AES的功能如下:
对称密钥对称分组密码
128位数据,128/192/256位密钥
比Triple-DES更强更快
提供完整的规格和设计细节
详细可以看 AES
这个密码系统是最初的系统之一。 即使在今天,它仍然是最多被使用的密码系统。 该系统由三位学者Ron Rivest,Adi Shamir和Len Adleman发明,因此被称为RSA密码系统。
下面给出生成RSA密钥对的一个例子(为了便于理解,这里采用的素数p&q值很小,实际上这些值非常高)。
设两个素数为p = 7且q = 13。因此,模数n = pq = 7×13 = 91。
选择 e = 5,这是一个有效的选择,因为没有数字是公因子5和(p - 1)(q - 1)= 6×12 = 72,除了1。
这对数字(n,e) = (91, 5)形成公钥,可以让任何我们希望能够向我们发送加密消息的人使用。
向扩展欧几里德算法输入p = 7,q = 13和e = 5。 输出将是d = 29。
因此,公钥是(91, 5),私钥是(91, 29)。
假设发送者希望发送一些文本消息给公钥为(n,e)的人。然后发件人将明文表示为一系列小于n的数字。
为了加密第一个明消茄文P,它是一个模n的数字。 加密过程是简单的数学步骤:
C = Pe mod n
换句话说,密文C等于明文P乘以自己e次,然后减去模n。 这意味着C也是一个小于n的数字。
回到我们的密钥生成例子,明文P = 10,我们得到密文C:
C = 105 mod 91
属于ECC的一种变化。加密的核心理念与RSA相似,也是利用离散对数很难求解。
但与RSA不同的野灶是 公钥的组成部分,EIGamal的公钥有三部分组成, 质模数 p, 生成元素 g, 以及 公共的 Y = gx(g的x次方) mod p。
详细可以看 ElGamal Crytosystem
椭圆曲线密码术(ECC)是用来描述一套密码工具和协议的术语,其安全性基于特殊版本的离散对数问题。它不使用数字模p。ECC基于与称为椭圆曲线的数学对象相关联的数字集合。有这些数字的加法和计算倍数的规则,就像数字模p一样。
ECC包含许多最初为模块化数字设计的密码方案的变体,如ElGamal加密和数字签名算法。
相信当应用于椭圆曲线上的点时,离散对数问题更加困难。这会提示从数字模p切换到椭圆曲线上的点。如果我们使用基于椭圆曲线的变体,也可以用较短的密钥获得等效的安全级别。
较短的密钥有两个好处:
易于管理
高效的计算
这些优点使基于椭圆曲线的加密方案变体对计算资源受到限制的应用程序非常有吸引力。
详细可以看 Elliptic Curve Cryptography
^符号表示为多少次方
签名 = 消息^D mod N (D和N 为签名者的私钥,计算消息的D次方并求mod N,所得余数即为签名)
消息 = 签名^E mod N (E和N 为签名者的公钥,计算签名的E次方并求mod N)
举个例子:
私钥: D = 29; N = 323
公钥: E = 5; N = 323
消息: 123
由于 N 的值为 323, 因此消息需要为 0 ~ 322 这个范围内的整数. 假设需要对 123 这个消息进行签名.
用私钥(D,N) = (29,323) 对消息 123 进行签名.
消息^D mod N = 123^29 mod 323 = 157
因此 (消息, 签名) = (123, 157)
用公钥(E,N) = (5,323)对消息进行验证
签名^E mod N = 157^5 mod 323 = 123
得到消息 123 与发送者发送过来的消息 123 是一致的,因此签名验证成功.
https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introction/
加法逆: a在集合中, -a在集合中的定义为使 a + (-a) = 0, 这就是加法逆元运算
乘法逆: a在集合中,且不为0, a^-1 在集合中定位为使 a* a^-1 = 1, 这就是乘法逆元运算
在聊椭圆曲线前,我们先打一些基础然后再讨论一下对数问题.
在一个集合上定义一个二元运算,这就是数学中的群。一个集合 G 要成为一个群,必须满足下面 4 个条件:
从平常的加法概念来看, 整数集 Z 是一个群(而且是阿贝尔群). 自然数集 N 不是一个群.
我们可以在椭圆曲线上定义一个群:
https://andrea.corbellini.name/ecc/interactive/reals-add.html
如下图: 点 A 的自我相加过程就是做 乘法的过程 这个过程叫 Point Doubling
计算 nP 需要做 n次加法 如果 n 为 k 位二进制 时间复杂度为 O(2^k)
倍加算法 比如 n = 151 二进制为 10010111
用倍加算法 时间复杂度有了很大的改进 O(logN) or O(k)
Q = nP
这只是 p = 211, 像 Secp256k1 这条椭圆曲线的 p = 34671663 一个78位的数字 要怎么求出 n?
一个通俗的比喻: 假设这些点是有个人 A 在一个很大的房间里玩弹珠的游戏 玩了两年 两年后 A 的朋友 B来了 B看到了最后的点 以及 A 告诉B 起点 但是B怎么能知道 A 是弹了多少次才从起点弹到终点?
上面这两张图是 椭圆曲线 - Secp256K1: y^2 = x^3 + 7
第一张图: 定义在 实数域
第二张图: 定义在 有限域Zp
是用下面的参数(p,a,b,G,n,h)形成的:
p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F = 2^256 - 2^32 - 997
a = 0
b = 7
G = [0x79BE667E_F9DCBBAC_55A06295_CE870B07_029BFCDB_2DCE28D9_59F2815B_16F81798,
0x483ADA77_26A3C465_5DA4FBFC_0E1108A8_FD17B448_A6855419_9C47D08F_FB10D4B8]
n = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_BAAEDCE6_AF48A03B_BFD25E8C_D0364141
h = 1
如果椭圆曲线上一点P, 存在最小的正整数 n 使得数乘 nP=O∞, 则将 n 称为 P 的阶
计算可得 27P = -P = (3, 13) 所以 28P = 0∞ P的阶为28
如何签名?
Sig = F sig ( F keccak256 ( m ) , k )
如何计算 r
如何计算 s
s ≡ q^-1 (Keccak256(m) + r * k) (mod p)
如何验证签名?
P.S. 上述验证签名的过程中 没有用到发送者的 私钥
RSA 密钥大小(bits) ECC 密钥大小 (bits)
1024 160
2048 224
3072 256
7680 384
15360 521
有一个研究例子 同一台计算能力的计算机
为什么 比特币和以太坊要选择 Secp256k1 这条椭圆曲线?
假如有人提供一条椭圆曲线比如 Secp256r1 如何验证这条曲线的安全性?
因为公钥是公开的,很容易被破坏或者篡改,因此需要建立和维持一种可信的基础机制来管理公钥。
PKI由5部分组成:
作为比喻,证书可以被视为发给该人的身份证。人们使用驾照,护照等身份证来证明自己的身份。数字证书在电子世界中具有相同的基本功能。
但有一点不同,数字证书不仅发给人,还可以发给电脑,软件包或任何其他需要证明电子世界身份的东西。
数字证书基于ITU标准X.509,该标准定义了公钥证书和认证验证的标准证书格式。因此数字证书有时也被称为X.509证书。
与用户客户端相关的公钥与证书颁发机构(CA)一起存储在数字证书中,以及其他相关信息,例如客户信息,到期日期,使用情况,发行者等。
CA对此整个信息进行数字签名并在证书中包含数字签名。
任何需要对客户的公共密钥和相关信息进行保证的人,他都会使用CA的公钥进行签名验证过程。成功的验证可确保证书中给出的公钥属于在证书中给出详细信息的人员。
下图了展示了个人/实体获取数字证书的过程:
如图所示,CA接受来自客户端的申请以证明其公钥。 CA在适当验证客户身份后,向该客户发出数字证书。
如上所述,CA向客户颁发证书并协助其他用户验证证书。 CA负责正确识别要求颁发证书的客户的身份,并确保证书中包含的信息是正确的并对其进行数字签名。
CA的关键功能:
证书类别
有四种典型的证书类别:
第1类 - 通过提供电子邮件地址可轻松获取这些证书。
第2类 - 这些证书要求提供额外的个人信息。
第3类 - 这些证书只有在对请求者的身份进行检查后才能购买。
第4类 - 它们被需要高度信任的政府和金融机构使用。
CA可以使用第三方注册机构(RA)对要求证书确认其身份的人或公司进行必要的检查。 RA可能在客户端看起来像一个CA,但它们实际上并不签署发布的证书。
这是发布证书的管理系统,暂时或永久暂停,续订或撤销证书。 证书管理系统通常不会删除证书,因为可能有必要在某个时间点证明其身份,这是出于法律原因。 CA和相关RA运行证书管理系统,以便能够跟踪他们的责任。
虽然客户端的公钥存储在证书中,但关联的私钥可以存储在密钥所有者的计算机上。 这种方法一般不采用。 如果攻击者能够访问计算机,他可以轻松访问私钥。 出于这个原因,私钥存储在通过密码保护的安全可移动存储令牌上。
不同的供应商经常使用不同的专有的存储格式来存储密钥。 例如,Entrust使用专有的.epf格式,而Verisign,GlobalSign和Baltimore使用标准的.p12格式。
1.6 Hierarchy of CA:
由于拥有庞大的网络和全球通信的要求,所有用户从唯一一个可信的CA获得证书是不切实际的。其次,只有一个CA的可用性可能会导致大的阻碍,如果CA受到影响。
在这种情况下,层次认证模型很受关注,因为它允许在两个通信方与相同CA没有信任关系的环境中使用公钥证书。
根CA位于CA层次结构的顶部,根CA的证书是自签名证书。
直接隶属于根CA(例如,CA1和CA2)的CA具有由根CA签名的CA证书。
层次结构中下级CA(例如,CA5和CA6)下的CA具有由上级下级CA签名的CA证书。
证书颁发机构(CA)层次体现在证书链中。证书链跟踪从层次结构中的分支到层次结构根的证书路径。
下图显示了具有从实体证书到两个从属CA证书(CA6和CA3)到根证书颁发机构CA证书的证书链的CA层次结构:
验证证书链是确保特定证书链有效,正确签署和可信的过程。 以下过程验证证书链,从提供验证的证书开始 -
一个正在验证其真实性的客户端提供他的证书,通常连同证书链一直到根CA.
验证者获取证书并使用发行者的公钥进行验证。 发行人的公钥在发行人的证书中找到,该证书位于客户证书旁边的链中。
现在,如果已签署发行人证书的较高的CA由验证方信任,则验证成功并在此停止。
否则,发行人证书的验证方式与客户在上述步骤中完成的相似。 此过程将继续进行,直到在其中找到可信的CA,否则它将持续到根CA。
哈希函数非常有用,并且出现在几乎所有信息安全应用程序中。
哈希函数是将数字输入值转换为另一个压缩数值的 数学函数。 哈希函数的输入具有任意长度,但输出始终为固定长度。
哈希函数返回的值称为消息摘要或简单的散列值。 下面的图片说明了哈希函数:
为了成为一个有效的加密工具,哈希函数具有以下属性:
散列的核心是一个数学函数,该函数在两个固定大小的数据块上运行以创建散列码。 这个哈希函数构成哈希算法的一部分。
每个数据块的大小因算法而异。 通常块大小从128位到512位。 下图演示了哈希函数:
哈希算法涉及上述哈希函数,如分组密码。 每一轮都会输入一个固定的大小,通常是最近消息块和最后一轮输出的组合。
这个过程重复进行多次,以散列整个消息。 哈希算法的示意图如下图所示:
因为第一消息块的散列值变成第二散列操作的输入,其输出改变第三操作的结果,等等。 这种效应被称为散列的雪崩效应。雪崩效应对两个即使是单个数据位也不相同的消息产生明显不同的散列值。理解哈希函数和算法之间的区别。 哈希函数通过对两个固定长度的二进制数据块进行操作来生成哈希码。哈希算法是一个使用哈希函数的过程,指定如何分解消息以及如何将先前消息块的结果链接在一起。
后来在1995年,SHA-1被设计用于纠正SHA-0的所谓弱点。SHA-1是现有SHA哈希函数中使用最广泛的。它被用于几个广泛使用的应用程序和协议,包括安全套接字层(SSL)安全。
2005年,发现了一种在实际时间框架内发现SHA-1冲突的方法,使SHA-1的长期可用性受到怀疑。
SHA-2系列具有四个更进一步的SHA变体,SHA-224,SHA-256,SHA-384和SHA-512,取决于其散列值中的位数。还没有成功的攻击报道过SHA-2哈希函数。
虽然SHA-2是一个强大的哈希函数。虽然有很大的不同,但其基本设计仍然遵循SHA-1的设计。因此,NIST要求提供新的竞争性散列函数设计。
2012年10月,NIST选择Keccak算法作为新的SHA-3标准。 Keccak提供了许多好处,例如高效的表现和良好的攻击抵抗力。
该集包括RIPEND,RIPEMD-128和RIPEMD-160。此算法还有256位和320位版本。
原始的RIPEMD(128位)基于MD4中使用的设计原则,并且发现提供可疑的安全性。 RIPEMD 128位版本是解决原始RIPEMD漏洞的快速修复替代品。
RIPEMD-160是一个改进版本,是使用最广泛的版本。与RIPEMD-128和RIPEMD-160相比,256和320位版本分别减少了意外冲突的可能性,但没有更高的安全等级。
Merkle Tree 默克尔树
哈希算法的一个重要应用是默克尔树(Merkle tree),默克尔树是一种数据结构,通常是一个二叉树,也有可能是多叉树,它以特定的方式逐层向上计算,直到顶部,最顶层叫做默克尔根(Merkle Root),默克尔树最为常见和最简单的是二叉默克尔树。