gitbook/分布式协议与算法实战/docs/215640.md
2022-09-03 22:05:03 +08:00

124 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 加餐 | 拜占庭将军问题:如何基于签名消息实现作战计划的一致性?
你好,我是韩健。
在[01讲](https://time.geekbang.org/column/article/195662)中,为了不啰嗦,让你举一反三地学习,我对签名消息型拜占庭问题之解,没有详细展开,而是聚焦在最核心的点“签名约束了叛徒的作恶行为”,但从留言来看,很多同学在理解签名和如何实现作战一致性上,还是遇到了问题。比如不理解如何实现作战计划的一致性。
另外考虑到签名消息是一些常用的拜占庭容错算法比如PBFT的实现基础很重要所以这节课我会对签名消息型拜占庭问题之解进行补充。在今天的内容中除了具体讲解如何基于签名消息实现作战计划的一致性之外我还会说一说什么是签名消息。希望在帮你掌握签名消息型拜占庭问题之解的同时还帮你吃透相关的基础知识。
当然在学完01讲之后相信你已经明白了签名消息拜占庭问题之解之所以能够容忍任意数量的叛徒关键就在于通过消息的签名约束了叛徒的作恶行为也就是说任何篡改和伪造忠将的消息的行为都会被发现。
既然签名消息这么重要,那么什么是签名消息呢?
## 什么是签名消息?
签名消息指的就是带有数字签名的消息,你可以这么理解“数字签名”:类似在纸质合同上进行签名来确认合同内容和证明身份。
在这里我想说的是数字签名既可以证实内容的完整性又可以确认内容的来源实现不可抵赖性Non-Repudiation。既然签名消息优点那么多**那么如何实现签名消息呢?**
你应该还记得密码学的学术CPBob和Alice不记得的话也没关系你把他们当作2个人就可以了今天Bob要给Alice发送一个消息告诉她“我已经到北京了”但是Bob希望这个消息能被Alice完整地接收到内容不能被篡改或者伪造我们一起帮Bob和Alice想想办法看看如何实现这个消息。
首先为了避免密钥泄露我们推荐Bob和Alice使用非对称加密算法比如RSA。也就是说加密和解密使用不同的秘钥在这里Bob持有需要安全保管的私钥Alice持有公开的公钥。
然后Bob用哈希算法比如MD5对消息进行摘要然后用私钥对摘要进行加密生成数字签名Signature就像下图的样子
![](https://static001.geekbang.org/resource/image/8d/75/8d69065c69944b74d77592a2aa5ea075.jpg "图1")
接着Bob将加密摘要和消息一起发送给Alice
![](https://static001.geekbang.org/resource/image/92/e0/924cd677d20a1fa7dca41936fc1e5ee0.jpg "图2")
接下来当Alice接收到消息和加密摘要Signature她会用自己的公钥对加密摘要Signature进行解密并对消息内容进行摘要Degist-2然后将新获取的摘要Degist-2和解密后的摘要Degist-1进行对比如果2个摘要Digest-1和Digest-2一致就说明消息是来自Bob的并且是完整的就像下图的样子
![](https://static001.geekbang.org/resource/image/fe/9d/fe974b9037e9ef4e85c227b5a867d39d.jpg "图3")
你看通过这种方法Bob的消息就能被Alice完整接收到了任何篡改和伪造Bob消息的行为都会因为摘要不一致而被发现。**而这个消息就是签名消息。**
现在你应该理解了什么是签名消息了吧另外关于在留言区提到的“为什么签名消息能约束叛将们的作恶行为在这里我再补充下通过上面的Bob和Alice的故事我们可以看到在数字签名的约束下叛将们是无法篡改和伪造忠将的消息的因为任何篡改和伪造消息的行为都会被发现也就是作恶的行为被约束了。也就是说叛将这时能做“小”恶比如不响应消息或者叛将们相互串通发送指定的消息但他们无法篡改或伪造忠将的消息了。
既然数字签名约束了叛将们的作恶行为,那么苏秦怎么做才能实现作战的一致性的呢?也就是忠将们执行一致的作战计划。
## 如何实现作战计划的一致性?
之前我已经提到了,苏秦可以通过签名消息的方式,不仅能在不增加将军人数的情况下,解决二忠一叛的难题,还能实现无论叛将数多少,忠诚的将军们始终能达成一致的作战计划。
为了方便你理解,我以二忠二叛(更复杂的叛徒作恶模型,因为叛徒们可以相互勾结串通)为例具体演示一下,是怎样实现作战计划的一致性的:
![](https://static001.geekbang.org/resource/image/25/f9/25bdee6e350e7d4f70401c649f40bef9.jpg "图4")
需要你注意的是4位将军约定了一些流程来发送作战信息、执行作战指令。
**第一轮:**
* 先发送作战指令的将军,作为指挥官,其他的将军作为副官。
* 指挥官将他的签名的作战指令发送给每位副官。
* 每位副官,将从指挥官处收到的新的作战指令(也就与之前收的作战指令不同),按照顺序(比如按照首字母字典排序)放到一个盒子里。
**第二轮:**
* 除了第一轮的指挥官外剩余的3位将军将分别作为指挥官在上一轮收到的作战指令上加上自己的签名并转发给其他将军。
**第三轮:**
* 除了第一、二轮的指挥官外剩余的2位将军将分别作为指挥官在上一轮收到的作战指令上加上自己的签名并转发给其他将军。
最后各位将军按照约定比如使用盒子里最中间的那个指令来执行作战指令。假设盒子中的指令为A、B、C那中间的指令也就是第n /2个命令。其中n为盒子里的指令数指令从0开始编号也就是B
为了帮你直观地理解,如何基于签名消息实现忠将们作战计划的一致性,我来演示一下作战信息协商过程。**而且我会分别以忠将和叛将先发送作战信息为例来演示,**这样可以完整地演示叛将对作战计划干扰破坏的可能性。
那么忠诚的将军先发送作战信息的情况是什么呢?
为了演示方便,假设苏秦先发起带有签名的作战信息,作战指令是“进攻”。那么在第一轮作战信息协商中,苏秦向齐、楚、燕发送作战指令“进攻”。
![](https://static001.geekbang.org/resource/image/66/be/66add595b082b18e3a6feaeb4b5e6ebe.jpg "图5")
在第二轮作战信息协商中齐、楚、燕分别作为指挥官向另外2位发送作战信息“进攻”。可是楚、燕已经叛变了**但在签名的约束下,他们无法篡改和伪造忠将的消息,**为了达到干扰作战计划的目的,他们俩一个选择发送消息,一个默不作声,不配合。
![](https://static001.geekbang.org/resource/image/6b/d0/6b5878c8dce6279dabc8db92d666cfd0.jpg "图6")
在第三轮作战信息协商中,齐、楚分别作为指挥官,将接收到的作战信息,附加上自己的签名,并转发给另外一位(这时的叛徒燕,还是默不作声,不配合)。
![](https://static001.geekbang.org/resource/image/35/23/355f1a1453547731c9a1d05090eaa123.jpg "图7")
最终,齐收到的作战信息都是“进攻”(它收到了苏秦和楚的),按照“执行盒子最中间的指令”的约定,齐会和苏秦一起执行作战指令“进攻”,实现忠将们作战计划的一致性。
那么如果是叛徒楚先发送作战信息,干扰作战计划,结果会有所不同吗?我们来具体看一看。在第一轮作战信息协商中,楚向苏秦发送作战指令“进攻”,向齐、燕发送作战指令“撤退”。(当然还有其他的情况,这里只是选择了其中一种,其他的情况,你可以都推导着试试,看看结果是不是一样?)
![](https://static001.geekbang.org/resource/image/d6/0b/d6e1997399d8e37177a4a1e98e31cb0b.jpg "图8")
然后,在第二轮作战信息协商中,苏秦、齐、燕分别作为指挥官,将接收到的作战信息,附加上自己的签名,并转发给另外两位。
![](https://static001.geekbang.org/resource/image/7e/2c/7e9066308ae3338a53c2e5561d43b22c.jpeg "图9")
**为了达到干扰作战计划的目的,叛徒楚和燕相互勾结了。**比如,燕拿到了楚的私钥,也就是燕可以伪造楚的签名,这个时候,燕为了干扰作战计划,给苏秦发送作战指令“进攻”,给齐发送作战指令却是“撤退”。
接着,在第三轮作战信息协商中,苏秦、齐、燕分别作为指挥官,将接收到的作战信息,附加上自己的签名,并转发给另外一位。
![](https://static001.geekbang.org/resource/image/bd/e3/bd82590e3db9184067d455cf0d3a74e3.jpg "图10")
最终,苏秦和齐收到的作战信息都是“撤退、进攻”,按照“执行盒子最中间的指令”的约定,苏秦、齐和燕一起执行作战指令“撤退”,实现了作战计划的一致性。也就是说,无论叛将楚和燕如何捣乱,苏秦和齐都能执行一致的作战计划,保证作战的胜利。
另外在这里我想补充一点签名消息的拜占庭问题之解也是需要进行m+1轮其中m为叛将数所以你看只有楚、燕是叛变的那么就进行了三轮协商。你也可以从另外一个角度理解n位将军能容忍(n - 2) 位叛将(只有一位忠将没有意义,因为此时不需要达成共识了)。**关于这个公式,你只需要记住就好了,推导过程你可以参考论文。**
最后,我想说的是,签名消息型拜占庭问题之解,解决的是忠将们如何就作战计划达成共识的问题,也就只要忠将们执行了一致的作战计划就可以了。但它不关心这个共识是什么,比如,在适合进攻的时候,忠将们可能执行的作战计划是撤退。也就是,这个算法比较理论化。
关于理论化这一点有的同学会想知道它如何去用在我看来呢这个算法解决的是共识的问题没有与实际场景结合是很难在实际场景中落地的。在实际场景中你可以考虑后来的改进过后的拜占庭容错算法比如PBFT算法。
## 内容小结
本节课我主要带你了解了什么签名消息,以及忠将们如何通过签名消息实现作战的一致性,我希望你明确这样几个重点:
1.数字签名是基于非对称加密算法比如RSA、DSA、DH实现的它能防止消息的内容被篡改和消息被伪造。
2.签名消息约束了叛徒的作恶行为,比如,叛徒可以不响应,可以相互勾结串通,但叛徒无法篡改和伪造忠将的消息。
3.需要你注意的是,签名消息拜占庭问题之解,虽然实现了忠将们作战计划的一致性,但它不关心达成共识的结果是什么。
最后我想说的是签名消息、拜占庭将军问题的签名消息之解是非常经典的基础知识影响和启发了后来的众多拜占庭容错算法比如PBFT理解了本讲的内容后你能更好地理解其他的拜占庭容错算法以及它们如何改进的为什么要这么改进比如在PBFT中基于性能的考虑大部分场景的消息采用消息认证码MAC只有在视图变更View Change等少数场景中采用了数字签名。
## 课堂思考
我演示了在“二忠二叛”情况下,忠将们如何实现作战计划的一致性,那么你不妨推演下,在“二忠一叛”情况下,忠将们如何实现作战计划的一致性呢?欢迎在留言区分享你的看法,与我一同讨论。
最后,感谢你的阅读,如果这篇文章让你有所收获,也欢迎你将它分享给更多的朋友。