# BTC 学习笔记连载(1)——古典密码学

By [Crypto 吊车尾](https://paragraph.com/@imsongoku) · 2022-08-31

---

欢迎交流：[twitter.com/songoku\_web3](http://twitter.com/songoku_web3)

我们说BTC是加密货币，

加密货币自然绕不开密码学，

密码学可以追溯到数千年前，

但成体系的发展却只是近几十年的事。

这个系列我会整理多篇文章，试图将**BTC的共识协议**、**数据结构**、**BTC网络**、**mining**等问题都讲清楚，我本身不是技术出身，会尽量避免过深的技术细节，从产品的角度给大家做一个梳理，也期望让非技术web3从业者或爱好者能够尽可能深入地理解BTC、理解区块链。

但开始讲BTC之前，还有一个认知基础需要先解决。

作为一个Crypto的从业者，我认为有必要深入了解一下整个密码学的发展史，包括主流密码技术的特点及演变，为什么基于密码学、基于数学的BTC是足够值得信赖的？是什么保障它的去中心化及安全性的？它又存在些什么问题？

所以前几篇先来梳理一下**密码学**。

什么是密码？

登录交易所时需要输入密码；

登录QQ、邮箱时也需要输入密码；

到银行ATM机取款时依然输入密码；

这是我们今天要讨论的密码吗？

显然不是！

严格来讲这仅仅是一个通行的口令，是可以称为password的私密的号码，是一个可以验证你身份的凭证。

**那什么是密码？**

密码是一种用来混淆的技术，使用者将原始信息加密转变成无法识别的信息，然后通过解密或破解又可以恢复到原始信息，也用 password 通称。

**什么又是密码学呢？**

密码学一词源自希腊文“krypto's”及“logos”两字，直译即为“隐藏”及“讯息”之意，所以你也可以认为密码学就是关于隐藏信息的学科。

古埃及、古希腊、隐写术、六韬、藏头诗
------------------

人类历史上最早的密码史大概要追溯到公元前1900年左右的古埃及，当时人们使用特殊字符和简单替换式密码来保护信息。贵族克努姆霍特普二世的墓碑上记载了在阿梅连希第二法老王朝供职期间它所建立的功勋，上面的象形文字与我们已知的埃及象形文字有所不同，那是由普通象形文字经过处理后刻录的，由一位技艺精湛的人书写，具体方法已不从知晓，后人推测这可能是庄严和权威的象征。

考古学家曾在美索不达米亚平原上发现一个公元前 1500 年左右的泥板，其上记录了一份加密陶器上釉工艺配方。

......

公元前490年前后古希腊发生了两件密码史上非常有影响力的情报事件：

1.  **头皮送信**
    
    希斯泰乌斯为了安全地把信息传送给米利都的阿里斯塔格鲁斯，怂恿他起兵反叛波斯人，想出一个绝妙的主意，他剃光奴隶的头发在头皮上刻下密信，待奴隶头发重新长出来之后才将他派往米利都。
    
2.  **木板涂蜡**
    
    头皮送信之后的几年，新任波斯国王薛西斯一世为了完成父亲大流士的遗愿，花了整整五年的时间来秘密招兵买马增加军备，准备对以雅典为首的希腊城邦发动一场大逆袭。
    
    流亡到波斯的斯巴达废王德玛拉托斯，希望将这一信息传送会希腊。
    
    最终通过把当地日常使用的蜡板里的蜡先全部刮掉，露出木头做的框架底板，然后在底板上写上波斯攻打希腊的计划，再用蜡重新把底板盖住......
    
    这个情报为希腊人赢得了宝贵的几个月，最终赢得了第2次希波战争。
    

![](https://storage.googleapis.com/papyrus_images/cfd8885831f9b2fb77997b5a65017beb9bce4c7475a8eaafd88299d2537b0fa4.png)

这2个事件直接催生了后来盛极一时的隐写术：

*   利用化学药水在信纸上书写，再通过特殊药水阅读
    
*   在书/报纸所选字母下面扎孔，以传递信息
    
*   通过女士的耳环隐藏信息
    
*   白醋鸡蛋法等
    

隐写术可谓是五花八门，只要是能用于隐藏信息的方式几乎都被用了一遍。

从古到今，军队都是密码应用最频繁的地方，中国古代军事著作《孙子兵法》有句名言：知己知彼，百战不殆；知彼而不被彼知，就是军队征战致胜的关键，这一切都建立在系统、严密的保密通信上。

约公元前1128—公元前1015，姜子牙著兵书《六韬》，以周文王/周武王与太公问答的形式阐述军事理论，其中《**龙韬•阴符**》篇和《**龙韬•阴书**》篇就讲述了君主如何在战争中与在外的将领进行保密通信，以阴书为例：

武王问太公：领兵深入敌国境内，君主和将帅分别统领的军队要配合作战，但是要想实施变化无穷的作战策略，谋取敌人意想不到的胜利，需要联络的事情就会很多，军队之间距离遥远也无法靠符传达复杂信息，该怎么办呢?

太公回答说：如果有军机大事需要联络，应该用书信而不用符。君主通过书信向主将传达指示，主将则通过书信向君主请示。书信都要拆分成三部分，并分派三人送达，只有这三部分合在一起才能读懂信的内容。这就是所谓的阴书，敌人再聪明也看不懂这种书

![](https://storage.googleapis.com/papyrus_images/e431372dd356aaa15f6969a3f86de84eed80efec59cb634eed8246e0f7567896.png)

公元前1000年的信息加密方式，竟然包含了一种现代密码学的前卫思想：\*\*秘密共享！\*\*将信息拆分并由不同的参与者持有，任何一方都无法恢复秘密信息，只有参与者协作才能还原信息。 这是中国古人智慧的表现。

中国古代也有独特的隐写术，比如以藏头诗、藏尾诗、绘画等方式，将信息隐藏在诗文或画卷中特定位置，一般人只注意诗文或绘画的表面意境，却忽略了隐藏其中的“原始”信息。

风流才子唐伯虎的一首诗，就是赤裸裸的例子：

**我**画蓝江水悠悠，

**爱**晚亭上枫叶愁。

**秋**月溶溶照佛寺，

**香**烟袅袅绕经楼。

(周星驰的《唐伯虎点秋香》，这个秋香是有说法的)

《水浒传》中梁山好汉带头大哥宋江久慕卢俊义威名，一心想招他上山坐头把交椅，共图大业替天行道，但卢俊义根本没有造反的心思.......宋江一筹莫展，智多星吴用一首诗就搞定了：

**芦**花丛中一扁舟，

**俊**杰俄从此地游，

**义**士若能知此理，

**反**躬难逃可无忧。

被官府拿到了证据，大兴问罪之师，到处捉拿卢俊义，终于把他逼上梁山。

虽然这些行动策略目的都是在保护信息，但这些方式都很简陋且容易被识破，纠其本质也并没有对明文进行任何加密，严格来讲都很难归为密码学。

长此以往就必将促使较难破解的古典密码学的诞生。

再补充一点，现代互联网中常用的水印技术，就是借鉴隐写术发展而来的。

> 斯巴达、雅典、伯罗奔尼撒战争、古典密码学
> --------------------

公元前405年，堪称古代世界大战的伯罗奔尼撒战争进入尾声，斯巴达军队逐渐占据优势并准备对雅典进行最后一击，原本资助斯巴达对抗雅典的波斯帝国当然不希望看到这种一边倒的局面，雅典和斯巴达在持续的战争中两败俱伤才是波斯帝国的如意算盘。

伯罗奔尼撒人当然也察觉到了这种变化，但是苦于搞不清波斯帝国的具体计划，也不好有任何应对之策。幸运的是斯巴达军队捕获了一名雅典信使，正从波斯去往雅典。斯巴达士兵仔细搜查了这名信使，除了一条布满杂乱无章的希腊字母的腰带外一无所获。

情报究竟藏在什么地方呢？统帅莱桑德注意到了那条腰带上杂乱的字母，并反复琢磨研究这些天书似的文字，但无论把这些字母怎样重排都解析不出任何有用信息，最后莱桑德放弃了并开始寻求其它途径，但当他无意中把腰带呈螺旋形缠绕在手中的剑鞘上时，见证奇迹的时刻到了。腰带上原本杂乱无章的字母组成了一段文字，这便是雅典间谍要送回的情报：波斯军队将在斯巴达发起最后攻击时，对斯巴达军队进行突袭。

根据这份情报斯巴达军队改变了作战计划，以迅雷不及掩耳之势拿下了毫无防备的“同盟”波斯军队，解除了后顾之忧。随后轻装上阵征伐雅典并取得了最后胜利。

这是有记载的人类历史上最早的密码情报（后发展为滚桶密码，也称为塞塔式密码），这绝对是一个可拆解的加解密过程：

1.  明文
    
    波斯军队将在斯巴达发起最后攻击时，对其进行突袭。
    
2.  加密
    
    通信—方将腰带缠绕在约定粗细的木棍上，
    
    然后将明文信息书写在腰带上。
    
3.  密文
    
    展开后腰带上杂乱无章的希腊字母
    
4.  解密
    
    收信—方将腰带缠绕在约定粗细的木棍上获取明文信息，
    
    如果不这么做就只能看到一些毫无规则的字母。
    
5.  密码
    
    那有人要问了，这个过程中加密用的密码是什么呢？
    
    就是双方约定好的在腰带上书写的方式、规则，包括木棍的粗细及字母书写规范
    
    可以说这就是“加密算法”，用来对明文进行加密。
    

是不是觉得有点不可思议，欢迎来到密码学！

近现代的密码电报就是受它的启发而发明的！

这是古典密码学的开端！

古典密码学主要应用到如下一些方法：

1.  **替换法**
    
    替换法很简单，就是根据对照表将原文替换为密文。
    
    如图，原文abcdefgh根据对照表就可以得到密文u2fkx8cq。
    
    不知道替换规则的人就无法获取原文信息。
    
    上面举例是用到单表替换，为了增强加密效果又发展出多表替换，即有多张原文密文对照表单，不同字母可以用不同表单的内容替换。
    
2.  **置换法**
    
    置换法也很简单，其实就是换位密码。
    
    最简单的就是逆序法，明文abcd置换后得到密文dcba。
    
    也可以用更复杂的换位算法，比如加入秘钥k对原文进行更复杂地重新排列。
    
    eg：加密函数 c = Ek(m)、解密函数 m = Dk(c)
    
    简单点理解就是打乱洗牌。
    
3.  **移位法**
    
    移位法也很简单，就是将原文按照固定数位对照字母表进行位移得到密文。
    
    著名的凯撒密码就是使用移位法的，显而易见移位位数就是其秘钥。
    
    由于只有26个字母所以凯撒密码只有25种密匙，最多将25种位移量检测一遍即可，这就是最简单的暴力破解。
    
    当然你可以使用更复杂的位移算法增强加密效果。
    
4.  **分组法**
    
    栅栏密码(Rail-fence Cipher)就是把要加密的明文分为N个一组，然后把每组的第1—N个字符分别组合，然后连接起来形成密文。
    
    明文：Doge To the moon elon cx on twitter
    
    分组为：Dog eTo the moo nel onc xon twi tte r
    
    第1组：Detmnoxttr
    
    第2组：oThoenowt
    
    第3组：goteolcmie
    
    最终密文：DetmnoxttroThoenowtgoteolcmie
    
    当你看到最终密文的时候，你知道它是什么意思么？在这个基础上还可以增加一些更复杂的算法加强加密效果。
    
    **分组法也是现代密码学中分组密码的基础。**
    

电影《让子弹飞》里边就有古典密码学的影子，大哥、二哥...兄弟们一起抓假麻匪的时候，吹的哨子本质上就是替换法，不同的哨子映射到不同的含义上。这个“映射替换表”假麻匪是整不懂的，所以姜文和兄弟们才可以安全地传递信息。

19世纪末之前大概都是由这些方法的组合进行加解密的，其基本特点是手工加密和解密，所以也可以称为手工密码时代。

当概率论等数学方法大规模应用之后，古典密码就有了破解之道，

但在整个密码史上，古典密码是使用最久最广泛的加密方式。

放到现在很多场景也绰绰有余了。

> Base64、Base58、BTC 编码
> --------------------

既然已经讲到了替换法，就顺便讲一下 Base58，BTC地址就是通过Base58Check 编码的。

Base58是Base64演变来的，所以先来看看Base64：

Base64 是最常见的用于传输 8位字节码的编码方式之一，Base64 就是一个基于64个可打印字符来表示二进制数据的方法，是从二进制到字符的编码过程。

**为什么需要Base64编码呢？**

我们平常说的HTTP协议是一个文本协议，在HTTP协议下需要将二进制数据转换为字符数据才能传输，但是直接转换也是不可行的，因为网络只能传输可打印字符。

什么是可打印字符呢？

在ASCII编码中规定，0~31、127这33个字符属于控制字符，32~126这95个字符属于可打印字符，也就是说网络传输只能传输这95个字符，不在这个范围内的字符就无法传输。

传统邮件就遵循这个规则，当邮件中要传输图片时，其二进制流的每个字节不可能全部是可见字符，这必然影响传送。如果能在不改变传统协议的情况下，做一种扩展方案来支持二进制文件的传送，把不可打印的字符用可打印字符来传输，最后再转换回原始二进制数据不就可以了？

Base64编码应运而生：

![](https://storage.googleapis.com/papyrus_images/20f6a42a1ee174ec8885ef983aab3488eeb4e85e5d0c99d002e1d08905792e45.png)

如图，对照Base64编码表可将二进制数（Binary字段）替换为可见字符（Char字段）。

Base64虽然本质上就是是古典密码学的替换法，但它并不是用于加密的，它的秘钥（这张映射表）是公开的，它是为了编码而生的。

细心的大兄弟肯定也注意到了表里的Binary是6位2进制数，

2^6 = 64，**Perfect！**

64个可见字符刚好对应表达6位2进制数。

但一个字节是8位二进制数，剩下2个bit怎么办？

Base64的编码过程直接解决了这个问题：

*   将待转换字符串按每3个字节分组，每组24个bit位
    
*   将24个bit位每6个一组，共分为4组
    
*   按Base64编码表映射对应的值
    

但是问题又来了，如果字符串不够3个字节呢？

如果要编码的字节数刚好是3的倍数，那就最好不过，如果不是可以直接按6位截取，最后不足6位的末尾补0：

![( 3字节倍数，非3字节倍数 )](https://storage.googleapis.com/papyrus_images/a0afc4b547327eb717770ee0add4013d3064a12a098ac13fc6889fa748fad257.png)

( 3字节倍数，非3字节倍数 )

如上图，“Man”这个字符串刚好3个字节，最终也刚好切分为4组6位二进制数，对应到上面的Base64编码表很容易就能得到“TWFu”。

但“BC”这个字符不是3个节点的整数倍，就会稍微麻烦一点，切分到第3组的时候只剩下“0011”，所以直接在末尾添加“00”得到“001100”，要强调的是最后一组6位二进制数是完全空缺的，这种情况直接以以“=”编码，最终得到Base64编码为“QkM=”。

### Base58 & Base58Check

Base58就是在Base64的基础上去掉容易混淆的字符，不使用数字"0"，大写字母"O"，大写字母"I"，和小写字母"l"，以及"+"和"/" 6个字符，本质上就是一张58进制的映射表：

![](https://storage.googleapis.com/papyrus_images/04d40bc07ec52ce289e578edae29cb7913c42530f02b24141e09111e95f2029d.png)

Base58 和Base64 也是一样的编码过程吗？

3秒钟思考一下？

……

……

……

我原本也认为一样的，但昨晚写 [Bitcoin私钥-公钥-地址](https://mirror.xyz/imsongoku.eth/-aMTAIyj8X25QQ2cZf9uvuwTU8uD6CjlpRwGc2AuT3E) 的时候总觉得哪里不对。

2^6 = 64，从二进制转换为64进制，这是非常自然地映射关系。

58不是2的整数次幂，这就尴尬了。

怎么办？

既然无法直接从二进制映射，就只能另寻它法，本质上Base64编码是64进制，Base58是58进制，以辗转相除法去处理它就好了，如果是一个二进制数：

*   先将二进制数转换成10进制
    
*   然后再用辗转相除法，除以58并记录下余数
    
*   再用商去除以58记录下每一轮的余数，直到商为0
    
*   将所有余数按Base58编码表映射对应的值
    

直接以十进制数1314520举例：

*   1314520 / 58 = 22664 余 8
    
*   22664 / 58 = 390 余 44
    
*   390 / 58 = 6 余 42
    
*   6 / 58 = 0 余 6
    

这样得到4组映射编号：6-42-44-8，对照Base58编码得到结果“**7jm9**”，以后表白又有新的暗号了。

那如果是一个字符串呢，怎么编码？

比如“i love u”，要不留个作业思考一下！

其中转换过程还比较麻烦，很容易整错，喜欢深入细节的欢迎Twitter交流。

BTC 由公钥生成地址的时候用到了SHA-256、RIPEMD-160：

**RIPEMD 160(SHA256(K))**

很显然最终地址是160位的二进制数，比如：

1000101000010010010101......1010010100110010111010101

这种二进制数用来表示地址，在可读性、易用性上都是不可行的。

所以中本聪改造了Base64，同时引入版本前缀及额外4个字节的检验码形成Base58Check编码（这个我们在后面讲[私钥-公钥-地址](https://mirror.xyz/imsongoku.eth/-aMTAIyj8X25QQ2cZf9uvuwTU8uD6CjlpRwGc2AuT3E)的时候详细展开），用Base58编码的地址看起来就舒服多了：

3AdwgfQ1tCxs7fNk8zZtL8dwEVVTyK5Uho

---

*Originally published on [Crypto 吊车尾](https://paragraph.com/@imsongoku/btc-1)*
