第一部分:为什么需要区块链
第1章 货币与信任的本质
1.1 一个思想实验:没有银行的世界
想象你是一个生活在公元前3000年美索不达米亚平原上的农民。你种了一批小麦,你的邻居是个铁匠,他打了一把犁。你们想交换——但问题来了:你的小麦和他的犁,谁更值钱?怎么换?换多少?
这就是**以物易物(Barter)**的经典困境,经济学家称之为"需求的双重巧合"(double coincidence of wants)。你必须恰好遇到一个人,他既有你想要的东西,又想要你手里的东西。这个概率在复杂社会里低得可怜。
货币的出现解决了这个问题。它不是某个天才某天突然拍脑袋想出来的,而是人类社会在反复试错中自发演化出的工具。贝壳、石块、布帛、铜钱、金银——历史上担任过"货币"角色的东西五花八门,但它们有一个共同点:大家都相信它有价值。
请注意这句话里最关键的词:相信。
货币的本质,从来不是什么实物,而是共识。金子之所以值钱,不是因为它能吃能穿,而是因为几千年来全人类都约定俗成地认为它值钱。这种共识一旦崩溃,黄金就只是一块闪亮的金属。
1.2 货币的三大功能与一个核心问题
经济学教科书告诉我们,货币有三大功能:
- 交换媒介(Medium of Exchange):省去以物易物的麻烦,让交易变得顺滑。
- 价值尺度(Unit of Account):给所有商品和服务定一个统一的"价格标签"。
- 价值储藏(Store of Value):把今天的劳动成果留到明天使用。
这三个功能听起来各不相关,但它们指向同一个底层需求:在时间和空间上传递价值。
你今天卖了一头牛,得到了一百枚铜钱。三个月后你用这一百枚铜钱买了一匹布。铜钱在这里充当了跨越时间的"价值容器"。同样,你把铜钱寄给远在另一座城市的朋友,铜钱又充当了跨越空间的"价值载体"。
但这里有一个核心问题,也是整部区块链史的起点:
谁来保证这个价值传递过程是可靠的?
铜钱可以被剪边(把边缘的铜偷偷剪掉,以次充好)。纸币可以被伪造。数字账本可以被篡改。价值在传递过程中,始终面临被"动手脚"的风险。
解决这个问题,人类发明了一个东西:可信第三方。
1.3 可信第三方:银行、国家与信任的外包
在古罗马,有一种叫做"argentarii"的银行家,他们坐在广场上,帮人保管财物、兑换货币、记录债务。你把钱存进去,他给你一张凭证。你拿着凭证,可以在另一城市的他的合伙人那里取钱。这就是早期的汇兑业务。
这种模式的本质是:把信任外包给一个中介。
你不需要相信对方,你只需要相信这个中介——银行、政府、或者某个有公信力的机构。这个中介维护一本账本,记录谁欠谁多少钱,谁有多少存款。所有的交易,本质上都是对这本账本的修改。
现代金融体系就建立在这个逻辑之上,只不过规模大了很多,技术复杂了很多。今天你用支付宝转账100块钱给朋友,实际上发生的是:
你的账户(支付宝/银行数据库) -100
朋友的账户(支付宝/银行数据库) +100
两个数字的修改,由一个你看不见的中央服务器完成。整个过程里,你信任的不是对方,而是阿里巴巴或者背后的银行系统。
这个系统运转了几百年,总体上是有效的。但它有几个结构性缺陷,这些缺陷在2008年金融危机之后被越来越多的人看见。
1.4 中心化信任体系的四大裂缝
裂缝一:单点故障(Single Point of Failure)
中央账本是一个极其脆弱的东西。如果银行的服务器宕机,或者被黑客攻击,或者遭遇自然灾害,整个系统就会瘫痪。2010年海地地震后,大量民众因为银行系统崩溃而无法取出自己的存款——钱"在那儿",但就是取不出来。
更极端的例子:政府可以冻结你的账户。这在战乱国家、专制政权下是真实发生的。你名义上的财产,实际上随时可以被没收。
裂缝二:信任的滥用(Abuse of Trust)
你把信任交给了银行,但银行并不总是值得信任。2008年金融危机的根源之一,就是大型金融机构利用自己的中介地位,将高风险资产包装成低风险产品,欺骗投资者。Lehman Brothers倒塌时,无数普通人的储蓄化为乌有。
中央银行可以超发货币,悄悄稀释你的购买力。津巴布韦在2008年通货膨胀率达到$2.2 \times 10^{11}$%,100万亿津元只够买几条面包。这是货币体系信任崩溃的极端案例,但它告诉我们:中心化的货币权力可以被严重滥用。
裂缝三:摩擦与排他(Friction and Exclusion)
全球有大约14亿成年人没有银行账户("unbanked"人口)。他们不是不想用银行,而是被排除在系统之外——门槛太高,手续太麻烦,或者住的地方根本没有银行网点。
国际汇款更是一个黑洞。你给身在菲律宾的家人汇款,可能要支付5%-10%的手续费,还要等3-5个工作日。这些费用,流进了Western Union和银行的口袋。
裂缝四:隐私的悖论(Privacy Paradox)
中心化的账本意味着所有人的财务记录都被某个机构掌握。你买了什么,在哪儿花的钱,和谁交易过——这些数据在银行和政府面前毫无秘密可言。你以为你在用别人的服务,实际上你的数据才是产品。
1.5 双花问题:数字货币面临的独特挑战
好,假设我们想绕过银行,自己建一套数字货币系统。最大的技术障碍是什么?
答案是双花问题(Double Spending Problem)。
在物理世界里,这个问题不存在。你把一张100元的钞票给了我,你手里就没有了,不可能同时给两个人。物理资产的转移是"排他"的。
但数字信息不同。数字文件可以被完美复制。如果你的"数字货币"只是一串数字,什么阻止你把同一串数字同时发给两个人?
传统的解决方案是:引入一个中心化的账本,由它来仲裁"这笔钱到底有没有被花掉"。银行就是这么干的——它维护一个权威版本的账本,你无法同时从两个ATM里取出同一笔钱,因为银行会检查你的余额。
问题又回来了:我们不想要中心化的机构,但没有中心化机构,谁来防止双花?
这就是比特币要解决的核心问题,也是区块链技术存在的根本原因。
在展开技术答案之前,我们先来理解"信任"这件事可以被分解成哪些要素。
1.6 信任的解构:什么让我们信任一个系统?
当你把钱存进银行,你信任的是一个由多个层次构成的复杂体系:
- 法律层:银行受到法律监管,如果违规会被惩罚。
- 技术层:银行有加密传输、防火墙、备份系统等技术保障。
- 声誉层:百年老店的口碑,让人觉得它不太可能倒闭或作恶。
- 保险层:存款保险制度,给你兜底。
这是一个多层次的信任堆栈,每一层都在给上一层背书。本质上,你信任的是"系统的综合可靠性"。
区块链的思路完全不同:不依赖任何单一机构的信誉,而是用数学和密码学来构建信任。
具体来说,区块链试图做到以下几点:
- 透明性:任何人都可以查看账本的全部历史,无法抵赖。
- 不可篡改性:一旦数据被写入,修改的代价极其高昂,几乎不可能。
- 去中心化:没有单一控制点,没有人可以随意修改规则。
- 无需许可:任何人都可以参与,不需要获得某个机构的批准。
这四点听起来很美好,但如何用技术实现?这是后续章节要一一拆解的内容。现在,我们先在概念层面理解一件事:
区块链是对"信任"的一种重新工程化。 它把人与人之间需要的信任,转化为人与数学之间的信任。数学不会说谎,不会被收买,不会睡觉,也不会偷懒。
1.7 货币的现代形态:从实物到数字
你银行卡里的余额,本质上是银行数据库里的一个数字。中国M2(广义货币供应量)超过了290万亿人民币,但实际流通的纸币大约只有10万亿左右。剩下的280多万亿,只存在于各种数字账本上。
换句话说,货币早就已经是数字的了,只不过这些数字被各家银行分别管理,彼此之间需要通过复杂的清算结算系统来协调(比如中国的CNAPS,美国的Fedwire)。
每次你刷卡消费,背后发生的不是真正意义上的"钱的转移",而是一系列数据库操作的级联更新。信用卡公司、发卡行、收单行、商户行,每个环节都要维护自己的账本,然后定期对账清算。
这套系统有效,但冗余。它的复杂性,很大程度上来自于"不同机构之间互不信任,需要反复核对"。
如果有一个所有人都信任、所有人都能看到的公共账本,这些中间环节是不是就可以大幅简化甚至消除?
这个问题,正是区块链试图回答的。
1.8 2008年:比特币的历史背景
2008年10月31日,一个自称"中本聪(Satoshi Nakamoto)"的人,在一个密码学邮件列表上发布了一篇九页的论文:
"Bitcoin: A Peer-to-Peer Electronic Cash System"
时间选得耐人寻味。就在几周前,Lehman Brothers宣告破产,全球金融危机全面爆发。全世界的人们开始质疑:我们托付给银行和政府的信任,究竟还值多少钱?
比特币创世区块(第0块)里,中本聪嵌入了一行文字:
The Times 03/Jan/2009 Chancellor on brink of second bailout for banks
这是2009年1月3日《泰晤士报》的头版标题——英国财政大臣正在考虑对银行进行第二轮紧急救助。这行字,既是时间戳,也是宣言:一个不需要救助、不需要信任政府的货币体系,从今天开始。
当然,中本聪的愿景是否实现、是否值得追求,至今仍有争议。但他提出的技术方案——区块链——已经远远超出了加密货币的范畴,影响到了金融、供应链、游戏、艺术等几乎所有领域。。
1.9 直觉预览:区块链如何解决信任问题
在进入下一章的密码学内容之前,我们先用一个非常直觉化的比喻来预演区块链的核心思想。
想象一个小镇,每个居民手里都有一本完全相同的账本,记录着小镇里所有人的资产状况。当有人要转账,他需要向全镇广播这笔交易。所有居民核实这笔交易的合法性(发送方确实有这么多钱),然后把这笔交易记录到自己的账本上。
在这个设计里:
- 没有中央机构:没有哪个人的账本是"权威版本",大家共同维护一致性。
- 防止篡改:你想修改账本,需要说服超过一半的居民一起改——这在人数足够多的时候,几乎不可能。
- 透明可查:任何人都能看到所有交易历史。
当然,现实中的区块链比这复杂得多。小镇居民可以面对面核实,但互联网上的节点如何在没有中心协调的情况下达成一致?如何防止有人冒充别人发起交易?
这些问题,都需要密码学来回答。
本章小结
货币的本质是共识,而维持共识的传统方式是依赖可信第三方——银行和国家。但这种中心化信任体系存在单点故障、信任滥用、金融排斥和隐私悖论等结构性缺陷。数字货币面临的"双花问题",使得在没有中心机构的情况下建立可靠的价值转移系统成为一大技术难题。区块链的核心思想,是用数学与密码学替代对机构的信任,将人际信任工程化为对算法的信任。
第2章 密码学基础:区块链的地基
2.1 为什么密码学是这里的关键
上一章我们留下了几个悬念:
- 如何证明"这笔交易确实是我发起的,不是别人冒充我"?
- 如何保证"一旦数据被写入,就无法被悄悄篡改"?
- 如何在完全不信任对方的情况下,安全地交换秘密?
这三个问题,分别对应密码学里的三个核心工具:数字签名、哈希函数、公钥密码学。
区块链的整个技术架构,几乎就是这三样东西的精妙组合。理解了它们,区块链的运作逻辑就会像拼图一样自然地嵌入到位。
本章不要求你成为密码学专家,但你需要建立起正确的直觉——知道这些工具能做什么、不能做什么、为什么可信。
我们从最基础的开始。
2.2 哈希函数:数字世界的指纹机器
2.2.1 什么是哈希函数
哈希函数(Hash Function)是一种数学函数,它接受任意长度的输入,输出一个固定长度的"摘要"(digest),通常称为哈希值或散列值。
用最简单的比喻来理解:哈希函数是一台绞肉机。你可以往里塞任何东西——一个字符、一部莎士比亚全集、一个1TB的视频文件——出来的永远是一块固定大小的"肉饼"。而且,你无法从肉饼反推原材料。
比特币使用的哈希函数是SHA-256(Secure Hash Algorithm 256-bit),输出是256位(32字节)的哈希值,通常用64个十六进制字符表示。
来看几个实际例子(你可以在命令行里验证):
$ echo -n "hello" | sha256sum
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
$ echo -n "hello!" | sha256sum
ce06092fb948d9ffac7d1a376e404b26b7575bcc11ee05a4615fef4fec3a308b
$ echo -n "区块链" | sha256sum
38c7b9d81a5e7e1a5b1e3c6f3a3e9b2a6b4c1d8e2f9a3b7c4d5e6f1a2b3c4d5
注意第一和第二个例子:输入只差了一个感叹号,输出却天差地别。这叫做雪崩效应(Avalanche Effect)——输入的微小变化会导致输出的巨大变化。这个性质至关重要。
2.2.2 密码学哈希函数的四大性质
一个好的密码学哈希函数必须满足以下四个性质:
性质一:确定性(Deterministic)
同样的输入,永远产生同样的输出。这是基本要求。
$H(x) = H(x) \quad \text{(对所有 } x \text{ 成立)}$
性质二:高效计算(Efficient Computation)
给定输入 $x$,计算 $H(x)$ 应该很快。在现代计算机上,SHA-256对任意输入的计算通常在微秒级别完成。
性质三:单向性(Pre-image Resistance)
给定哈希值 $h$,找到任意 $x$ 使得 $H(x) = h$,在计算上不可行。
这意味着你不能"逆向"哈希函数。如果有人给你一个SHA-256的输出,你无法推算出原始输入(除非穷举所有可能性,而SHA-256有 $2^{256}$ 种可能的输出,穷举所有比宇宙中原子数还多)。
性质四:抗碰撞性(Collision Resistance)
找到两个不同的输入 $x$ 和 $y$,使得 $H(x) = H(y)$,在计算上不可行。
注意:理论上碰撞一定存在(无限输入映射到有限输出,必然有重叠),但找到一对碰撞在实践中是不可能的。SHA-256迄今未发现任何实际碰撞。
2.2.3 哈希函数在区块链中的作用
哈希函数是区块链的完整性保障机制。具体有以下几个关键用途:
用途一:数据完整性验证
你下载了一个5GB的软件安装包,怎么知道它没有被篡改?软件官网会提供SHA-256校验值。你本地计算下载文件的哈希,和官网公布的对比,一致则完整。
区块链用同样的逻辑:每个区块都包含前一个区块内容的哈希值。如果有人篡改了历史区块的内容,哈希值就会改变,后续所有区块就会"对不上号",篡改立即暴露。
用途二:区块的"链接"
每个区块包含前一个区块的哈希值,这正是"区块链"这个名字的来源。用伪代码表示:
class Block:
def __init__(self, data, prev_hash):
self.data = data
self.prev_hash = prev_hash # 前一个区块的哈希值
self.hash = sha256(self.data + self.prev_hash) # 本块的哈希值
这样形成一条链:
Block 0 (Genesis) Block 1 Block 2
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ data: "..." │ │ data: "..." │ │ data: "..." │
│ prev: 0x000... │──────▶│ prev: 0xA3F... │──────▶│ prev: 0xB7C... │
│ hash: 0xA3F... │ │ hash: 0xB7C... │ │ hash: 0xD1E... │
└──────────────────┘ └──────────────────┘ └──────────────────┘
用途三:工作量证明(挖矿)
比特币的挖矿过程,本质上是寻找一个特殊的输入,使得哈希输出满足某个条件(比如以若干个零开头)。这个过程我们在第5章详细展开。
2.3 公钥密码学:在不安全的信道上安全通信
2.3.1 对称加密的困境
在公钥密码学出现之前,加密通信使用的是对称加密(Symmetric Encryption):通信双方使用同一把密钥加密和解密。
发送方 接收方
明文 ──[密钥K加密]──> 密文 ──────> [密钥K解密] ──> 明文
问题在于:双方需要事先共享这把密钥。但如何安全地传输密钥?你无法通过不安全的网络传输密钥,因为密钥本身也会被截获。
这是个经典的"先有鸡还是先有蛋"问题:安全通信需要密钥,传输密钥需要安全通信。
2.3.2 公钥密码学的天才想法
1976年,Whitfield Diffie 和 Martin Hellman 提出了一个革命性的思想:加密和解密不必使用同一把密钥。
设想你有一把挂锁和它的钥匙。你可以把挂锁(开着的,不带钥匙)公开分发给所有人。任何人都可以用这把挂锁锁住一个盒子,但只有你有钥匙能打开它。
这就是公钥密码学的核心比喻:
- 公钥(Public Key):相当于开着的挂锁,可以公开。任何人都可以用它来给你"加密"(锁住盒子)。
- 私钥(Private Key):相当于钥匙,必须严格保密。只有你能用它来"解密"(打开盒子)。
实际使用时,你会用私钥锁(进行数字签名),别人用公钥开(只要能打开,就代表一定是你,因为私钥只有你有)
数学上,这一对密钥满足:
$\text{Decrypt}(\text{PrivKey}, \text{Encrypt}(\text{PubKey}, m)) = m$
并且,已知公钥,在计算上不可能推导出私钥。
2.3.3 RSA:第一个公钥密码系统
1977年,Rivest、Shamir 和 Adleman 发明了RSA算法,这是第一个实用的公钥密码系统。
RSA的安全性基于一个数论难题:大整数的质因数分解(Integer Factorization) 极其困难。
给你一个大整数 $n$,告诉你 $n = p \times q$,其中 $p$ 和 $q$ 都是质数,请找出 $p$ 和 $q$。
当 $n$ 只有几十位时,这很容易。但当 $n$ 有2048位(约620个十进制数字)时,即使用全球最强的计算机,分解它也需要比宇宙年龄还长的时间。
RSA密钥生成简化流程:
# ----------------------------------------
# 第一阶段:准备"造锁材料"——选质数,算 n
# ----------------------------------------
# 随机选两个质数,现实中是几百位的天文数字,这里用小数字演示
p = 61
q = 53
# 相乘得到 n,这个数是完全公开的
# n 的作用:所有加密/解密运算都在 mod n 的范围内进行
# 安全性来源:外人只知道 n=3233,但无法反推出 61 和 53
# (数字足够大时,质因数分解在计算上不可行)
n = p * q # = 3233
# ----------------------------------------
# 第二阶段:造"临时机床"——计算 φ(n)
# ----------------------------------------
# φ(n) 是造密钥对的临时工具,用完必须销毁,绝对不能公开
# 计算公式固定:(p-1) × (q-1),由 p 和 q 唯一决定,没有自由度
#
# 为什么必须保密?
# 因为知道 φ(n) 就能推出私钥 d,整个加密体系就崩溃了
# 而外人要想算出 φ(n),必须先知道 p 和 q
# 要知道 p 和 q,就必须对 n 做质因数分解——这正是那道难题
phi_n = (p - 1) * (q - 1) # = 60 × 52 = 3120
# ----------------------------------------
# 第三阶段:用"机床"造出密钥对
# ----------------------------------------
# 选公钥指数 e,唯一约束是:e 必须与 φ(n) 互质(没有公因数)
# 现实中 e 几乎固定选 65537,这里用 17 简化演示
# e 是完全公开的,没有任何秘密可言
e = 17 # 公钥指数
# 用 φ(n) 计算私钥指数 d
# 数学要求:e × d 除以 φ(n) 余 1,写作 e×d ≡ 1 (mod φ(n))
# 验证:17 × 2753 = 46801 = 15 × 3120 + 1 ✓
# 这个关系保证了"用 e 锁上的东西,d 一定能打开"
# 没有 φ(n) 就无法计算 d,这是私钥安全性的根本
d = 2753 # 私钥指数
# 至此:
# 公钥 (n=3233, e=17) → 公开发布,任何人都能拿到
# 私钥 (n=3233, d=2753) → 只有你保管
# φ(n) = 3120 → 销毁,不留任何记录
# ----------------------------------------
# 第四阶段:加密(任何人都能做)
# ----------------------------------------
# 假设有人想给你发一条消息,明文是数字 65
m = 65
# 对方只需要你的公钥 (n, e),套入公式:密文 = 明文^e mod n
# 这一步任何人都能做,因为 e 和 n 都是公开的
c = pow(m, e, n)
print(f"加密结果:{m}^{e} mod {n} = {c}") # = 2790
# 密文 2790 看起来和原来的 65 毫无关联
# 即使截获了密文,没有私钥 d 也无法还原
# ----------------------------------------
# 第五阶段:解密(只有你能做)
# ----------------------------------------
# 只有你有私钥 d,套入公式:明文 = 密文^d mod n
m_recovered = pow(c, d, n)
print(f"解密结果:{c}^{d} mod {n} = {m_recovered}") # = 65 ✓
# 为什么能还原?
# 数学上可以证明:只要 e 和 d 满足之前那个关系(e×d ≡ 1 mod φ(n)),
# 则对任意明文 m,都有 (m^e)^d mod n = m
# 这是欧拉定理保证的,是整个 RSA 的数学基础
再浅谈一下RSA 的历史地位:
RSA 发明于 1977 年,是第一个真正可以工程落地的公钥加密方案。它把 Diffie-Hellman 那个"两把钥匙"的革命性想法,变成了一套任何人都能实现的具体算法。在随后几十年里,它几乎支撑了整个互联网的安全基础设施——HTTPS、电子邮件加密、数字签名全都用它。
这个地位是无可争议的。
RSA 的核心问题:密钥必须越来越长
RSA 的安全性完全依赖"大数分解很难"这一点。但随着计算机算力的提升和分解算法的进步,"足够难"这个门槛不断提高:
| 年代 | 推荐密钥长度 |
|---|---|
| 1990 年代 | 512 位 |
| 2000 年代 | 1024 位 |
| 现在 | 2048 位起步,推荐 4096 位 |
密钥越长,计算量越大。在 PC 上感觉不明显,但在资源受限的场景里就是硬伤:
- 智能卡、IoT 设备、嵌入式芯片——运算能力弱,电池有限
- HTTPS 握手——每次建立连接都要做一次公钥运算,大规模服务器压力显著
- 区块链——每笔交易都要签名验证,效率直接影响吞吐量
椭圆曲线被引入的原因(下一小节详细讲解)
椭圆曲线密码学(ECC)基于另一个数学难题——椭圆曲线上的离散对数问题,这个问题目前比大数分解"难得多"。
结果就是,用小得多的密钥就能达到同等安全强度:
| 安全强度 | RSA 密钥长度 | ECC 密钥长度 |
|---|---|---|
| 128 位安全 | 3072 位 | 256 位 |
| 256 位安全 | 15360 位 | 521 位 |
密钥小了一个数量级,带来的好处是连锁的:计算更快、占用带宽更少、更适合嵌入式设备。
比特币用的就是 ECC(具体是 secp256k1 曲线),你的每一个比特币地址背后都是一个 256 位的椭圆曲线密钥对。
一个悬在头上的威胁:量子计算
RSA 和 ECC 其实面临同一个长期威胁——量子计算机。
Shor 算法理论上可以在多项式时间内解决大数分解和离散对数问题,意味着RSA 和 ECC 都会同时失效。这也是为什么密码学界现在在推进"后量子密码学"(Post-Quantum Cryptography),用完全不同的数学问题来构建新一代加密体系。不过量子计算机真正威胁到现有加密还有相当距离,目前 ECC 仍是工程实践的主流选择。
2.3.4 椭圆曲线密码学(ECC):比特币的选择
首先,"椭圆曲线"长什么样
名字听起来很唬人,但先看图:
$y^2 = x^3 + ax + b$
这是一条关于 xx x 轴上下对称的曲线。不同的 a、b 参数会改变形状,但对称性始终保持。比特币用的 secp256k1 令 a=0、b=7,所以方程极简:
$y^2 = x^3 + 7$
画出来大概长这样:
| ___
| /
---+-----/----------
| |
| \___
|
上下对称,右侧有一条从下往上延伸的曲线。
注意:这条曲线和"椭圆"没有任何关系,名字只是历史遗留问题。
现实中的曲线:从连续到离散
上面那条曲线是画在普通坐标系里的,点的坐标可以是任意实数。
但密码学需要的是整数——计算机只能处理离散的数字,不能处理无限精度的小数。
所以实际使用的椭圆曲线是这样的:
$y^2 \equiv x^3 + 7 \pmod{p}$
后面那个 (modp)的意思是:所有运算结果都对质数 p 取余。
效果是:原本连续的曲线,变成了一堆散落在正方形网格里的离散点。比特币选的那个 pp p 是:
$p = 2^{256} - 2^{32} - 977$
这是一个 78 位十进制数。这个正方形网格里大约有 $2^{256}$ 个点——比宇宙中的原子数量还多。
最关键的操作:点加法
ECC 的一切都建立在一个奇特的操作上:曲线上两个点相加,得到第三个点。
这个"加法"和普通加法完全不同,它的定义是几何的:
过曲线上的两个点 P 和 Q 画一条直线,这条线会和曲线交于第三个点,把这个交点关于 x 轴翻转,得到的就是 P + Q。
为什么要翻转?这是为了让这个加法满足数学上的一些好性质(比如结合律),方便后续推导。记住这个规则就行。
从点加法到标量乘法
有了点加法,就可以定义标量乘法:
k⋅G=G+G+G+⋯+G(k个G)
G 是曲线上一个公开约定的点,叫基点(生成元)。比特币的 secp256k1 里,G 的坐标是一个固定的、全世界都知道的值。
k 是一个正整数,标量乘法就是把 G 自己加 k 次。
现实中 k 可以高达 $2^{256}$,不可能真的加这么多次。实际用的是快速幂的思路:
算 k = 13 = 8 + 4 + 1
13·G = 8·G + 4·G + 1·G
而:
2·G = G + G (1次加法)
4·G = 2·G + 2·G (1次加法)
8·G = 4·G + 4·G (1次加法)
总共只需要几次加法,而不是 13 次
即使 k 是 256 位的天文数字,也只需要大约 512 次点加法就能算完。计算正向非常快。
安全性的来源:离散对数问题
现在来到核心问题:
已知 G 和 k⋅G,能反推出 k 吗?
正向(已知 k,算 k⋅G):几百次点加法,毫秒级完成。
反向(已知 k⋅G,找 k):目前没有任何已知算法能在合理时间内做到。唯一的方法是从 GG G 开始一步步加,逐个尝试——而候选的 k 有 $2^{256}$ 个,就算用全宇宙的计算资源穷举也远远不够。
这就是椭圆曲线离散对数问题(ECDLP),是 ECC 一切安全性的根基。
公钥和私钥是怎么来的
理解了标量乘法,公私钥的生成就一句话:
私钥 k ×G = 公钥 K
- 私钥:一个 256 位的随机整数,你自己随机生成,严格保密
- 公钥:把私钥乘以基点 GG G,得到曲线上的一个点 (x, y) ,可以公开
从私钥推公钥:做几百次点加法,极快。
从公钥推私钥:解 ECDLP,目前不可能。
这就是整个 ECC 的核心不对称性。
和 RSA 的本质区别:
| RSA | ECC | |
|---|---|---|
| 数学难题 | 大数质因数分解 | 椭圆曲线离散对数 |
| 128位安全所需密钥 | 3072 位 | 256 位 |
| 直觉 | 大数乘法容易,分解难 | 点加法容易,逆向找步数难 |
| 比特币使用 | ✗ | ✓(secp256k1) |
密钥短意味着:签名更小、验证更快、存储更省——对于每秒要处理大量交易的区块链来说,这不是锦上添花,而是工程上的必要选择。
2.4 数字签名:我怎么证明"这是我说的"
2.4.1 现实世界的签名有什么问题
在现实世界里,你在合同上签字,证明你认可这份合同的内容。但传统签名有两个弱点:
- 可伪造:有人可以临摹你的签名。
- 不能绑定内容:你可以把签好字的空白纸条交给别人,他们在上面随便写。
数字签名解决了这两个问题,而且安全性从数学上可以证明。
2.4.2 数字签名的运作原理
数字签名使用公钥密码学,但用法和加密"反过来":
- 签名:用私钥对消息进行签名(相当于"加密")。
- 验证:用公钥验证签名(相当于"解密")。
因为只有持有私钥的人才能产生有效签名,所以签名证明了身份。因为签名是对消息内容的哈希进行的,所以签名也绑定了消息内容——任何对消息的修改都会使签名失效。
流程如下:
签名方(持有私钥):
1. 计算消息的哈希: h = Hash(message)
2. 用私钥签名: signature = Sign(PrivKey, h)
3. 广播 (message, signature)
验证方(持有公钥):
1. 计算消息的哈希: h' = Hash(message)
2. 用公钥验证: valid = Verify(PubKey, signature, h')
3. 如果 valid == True,则签名有效
用一个具体的Python示例展示(使用ecdsa库):
from ecdsa import SigningKey, SECP256k1
import hashlib
# 生成密钥对
private_key = SigningKey.generate(curve=SECP256k1)
public_key = private_key.get_verifying_key()
# 消息
message = b"Alice pays Bob 1 BTC"
# 签名
signature = private_key.sign(message, hashfunc=hashlib.sha256)
print(f"签名(十六进制): {signature.hex()}")
# 验证
try:
public_key.verify(signature, message, hashfunc=hashlib.sha256)
print("签名有效 ✓")
except:
print("签名无效 ✗")
# 篡改消息后验证
tampered_message = b"Alice pays Bob 100 BTC" # 被人改了!
try:
public_key.verify(signature, tampered_message, hashfunc=hashlib.sha256)
print("签名有效 ✓")
except:
print("签名无效 ✗ (消息被篡改!)")
输出结果:
签名(十六进制): 3045022100...(64字节)
签名有效 ✓
签名无效 ✗ (消息被篡改!)
2.4.3 数字签名在比特币中的应用
在比特币里,每一笔交易都必须附带发送方的数字签名:
交易内容: "Alice 的地址 → Bob 的地址,金额: 1 BTC"
Alice 的签名: Sign(Alice的私钥, Hash(交易内容))
网络中的其他节点收到这笔交易时,用 Alice 的公钥验证签名:
- 签名有效 → 确认是 Alice 本人发起的交易,且交易内容未被篡改。
- 签名无效 → 拒绝这笔交易。
这样,无需任何中心机构认证,任何人都可以独立验证任何交易的合法性。这是去中心化的关键一环。
2.5 比特币地址:从公钥到地址的转化
你可能注意到,比特币地址看起来像这样:
1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf Na
这不是公钥本身(公钥是65字节的椭圆曲线点),而是对公钥进行一系列变换后的结果。为什么要这么做?
原因一:缩短长度。公钥太长,不方便人类阅读和传输。
原因二:额外的安全层。即使将来某种攻击方法能从地址推算出公钥,从公钥到私钥仍然是不可能的(两层保护)。
原因三:内置校验。比特币地址包含校验码,如果你输错了一个字符,钱包软件会立即检测到并提示错误,避免资产损失。
完整的推导流程:
私钥(256位随机数)
│
▼ 椭圆曲线乘法(secp256k1)
公钥(65字节 = 1字节前缀 + 32字节x坐标 + 32字节y坐标)
│
▼ SHA-256
(32字节哈希)
│
▼ RIPEMD-160
(20字节哈希,即"公钥哈希")
│
▼ 添加版本字节(0x00)+ 计算校验码(双重SHA-256取前4字节)
│
▼ Base58Check 编码
比特币地址(25-34个字符)
用伪代码表示关键步骤:
import hashlib
def pubkey_to_address(public_key_bytes):
# Step 1: SHA-256
sha256_hash = hashlib.sha256(public_key_bytes).digest()
# Step 2: RIPEMD-160
ripemd160 = hashlib.new('ripemd160')
ripemd160.update(sha256_hash)
pubkey_hash = ripemd160.digest() # 20字节
# Step 3: 添加版本字节
versioned = b'\x00' + pubkey_hash # 21字节
# Step 4: 计算校验码(双重SHA-256的前4字节)
checksum = hashlib.sha256(hashlib.sha256(versioned).digest()).digest()[:4]
# Step 5: 拼接并进行Base58Check编码
payload = versioned + checksum # 25字节
address = base58check_encode(payload)
return address
为什么用Base58而不是Base64?因为Base58去掉了容易混淆的字符:0(零)、O(大写O)、I(大写i)、l(小写L)——这些字符在某些字体下难以区分,容易导致手动输入错误。
2.6 Merkle树:高效验证大量数据
2.6.1 问题的引入
比特币的一个区块可能包含数千笔交易。假设你是一个"轻节点"(比如手机上的比特币钱包),你没有存储完整的区块链,只有区块头的数据。现在你想知道:某笔特定的交易(比如你收到的那笔钱),是否真的包含在某个区块里?
最笨的方法:下载整个区块的所有交易,逐一核对。对于一个几十兆的区块,这对手机用户来说既慢又费流量。
有没有更聪明的方法,让你只需要验证少量数据,就能确认某笔交易在区块里?
有,这就是Merkle树(Merkle Tree),由计算机科学家Ralph Merkle在1979年发明。
2.6.2 Merkle树的构建
Merkle树是一种二叉哈希树。构建方式如下:
- 对每笔交易计算哈希,得到叶子节点。
- 将相邻的两个叶子节点的哈希拼接,再次哈希,得到父节点。
- 重复第2步,直到只剩一个节点,即Merkle根(Merkle Root)。
图示(以4笔交易为例):
Merkle Root
Hash(AB + CD)
/ \
Hash(A + B) Hash(C + D)
/ \ / \
Hash(Tx_A) Hash(Tx_B) Hash(Tx_C) Hash(Tx_D)
| | | |
Tx_A Tx_B Tx_C Tx_D
比特币区块头只存储Merkle根(32字节),而不是所有交易的哈希。
2.6.3 Merkle证明:高效验证
现在,如果你想验证 $Tx_C$ 是否在这个区块里,只需要:
- 从全节点获取 $Tx_C$ 的哈希、$Tx_D$ 的哈希、以及 $Hash(A+B)$(即"Merkle证明路径")。
- 计算:$Hash(Tx_C + Tx_D) = Hash(C+D)$
- 计算:$Hash(Hash(A+B) + Hash(C+D)) = \text{Merkle Root}$
- 把计算出的Merkle Root与区块头里存储的对比——一致,则证明 $Tx_C$ 确实在这个区块里。
关键点:你只需要下载 $O(\log n)$ 个哈希值,就能验证$n$笔交易中的任意一笔!对于一个包含4096笔交易的区块,你只需要12个哈希值($\log_2 4096 = 12$),就能完成验证。
def verify_merkle_proof(tx_hash, proof, merkle_root):
"""
tx_hash: 要验证的交易哈希
proof: [(sibling_hash, is_left), ...] 路径
merkle_root: 区块头里的Merkle根
"""
current = tx_hash
for sibling, is_left in proof:
if is_left:
# 兄弟节点在左边
current = sha256(sibling + current)
else:
# 兄弟节点在右边
current = sha256(current + sibling)
return current == merkle_root
Merkle树是SPV(Simple Payment Verification,简单支付验证)的基础,让手机等轻量级设备也能参与比特币网络,而无需下载完整的400GB+区块链数据。
2.7 随机性与密钥生成的安全性
密码学的一切安全性,最终都依赖于一件事:高质量的随机数。
比特币私钥是一个256位的随机整数,取值范围是 $[1, n-1]$,其中 $n$ 是secp256k1的群阶:
$n = \text{FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141}_{16}$
这个范围大约是 $10^{77}$,比宇宙中的原子数量(约$10^{80}$)稍小一些。
如果随机数生成器有缺陷,攻击者就可能缩小搜索空间,暴力破解私钥。历史上真实发生过这样的案例:
案例:Android随机数漏洞(2013年)
早期的Android比特币客户端使用了Java的SecureRandom类,但在某些Android版本上,这个类存在实现缺陷,导致生成的随机数熵值不足。攻击者利用这个漏洞,成功预测了部分用户的私钥,盗取了比特币。
教训:密码学安全性的薄弱环节往往不在算法本身,而在实现细节。
安全的密钥生成应该使用操作系统级别的密码学随机数生成器:
import os
import secrets
# 不安全: 使用普通随机数
# import random
# private_key = random.getrandbits(256) # ❌ 绝对不要这样做!
# 安全: 使用操作系统的密码学随机数
private_key_bytes = os.urandom(32) # 32字节 = 256位
private_key = int.from_bytes(private_key_bytes, 'big') # ✓
# 或者更现代的写法
private_key_alt = secrets.randbits(256) # ✓
2.8 密码学的边界:它能做什么,不能做什么
在结束本章之前,我们需要澄清几个常见的误解:
误解一:加密就是绝对安全
密码学算法本身可能是安全的,但整个系统的安全性取决于最薄弱的环节。私钥被盗、实现有bug、用户被社会工程攻击——这些往往比算法破解更常见。比特币从未被"破解",但交易所和钱包被黑客攻击的事件屡见不鲜。
误解二:量子计算机会破解所有加密
量子计算机确实对某些密码系统构成威胁。Shor算法理论上可以在多项式时间内破解RSA和ECC(因为它能高效解决整数分解和离散对数问题)。但量子计算机目前离实用还很遥远,研究人员也已经在开发"后量子密码学"算法。NIST已于2024年正式发布了首批后量子密码学标准。
误解三:哈希函数可以保证隐私
哈希函数只能证明"数据没有被篡改",并不保护数据的内容。如果原始数据集很小(比如0到9之间的一个数字),攻击者可以对所有可能的输入逐一哈希,轻松找到匹配(这叫彩虹表攻击)。密码存储需要使用专门的慢哈希函数(如bcrypt、Argon2),而不是SHA-256。
误解四:公钥就是地址
在比特币里,公钥和地址是不同的东西(如2.5节所示)。你可以公开地址(用于接收资金),但在实际花费时才需要暴露公钥。这提供了一层额外的保护。
2.9 把所有碎片拼在一起
现在,我们把本章介绍的所有工具,放到比特币的框架里做一个整体预览:
私钥 k(256位随机数)
│ 椭圆曲线乘法
▼
公钥 K = k × G
│ SHA-256 + RIPEMD-160 + Base58Check
▼
比特币地址(你公开给别人用于收款)
当你要发送比特币时:
交易内容(包含输入、输出、金额等)
│ SHA-256 双重哈希
▼
交易哈希
│ 用私钥 k 签名(ECDSA算法)
▼
数字签名(附在交易里)
网络中的节点验证时:
1. 用发送方公钥验证签名 → 证明身份
2. 检查发送方余额(查阅UTXO集合)→ 防止双花
3. 验证交易格式合法 → 基本合规检查
4. 如果全部通过 → 将交易广播并最终打包进区块
所有这些验证,都在没有任何中心机构参与的情况下,由任意节点独立完成。密码学,将信任从人的手中,转移到了数学的手中。
本章小结
密码学是区块链的技术基石,提供了三个核心能力:哈希函数保证数据完整性并形成区块之间不可篡改的链接;公钥密码学(特别是椭圆曲线密码学)建立了身份认证机制,使得每个用户都能在无需第三方的情况下控制自己的资产;数字签名将身份与具体交易内容绑定,防止伪造和中途篡改。Merkle树则进一步提供了对海量交易数据的高效验证能力。这些工具的组合,使得"用数学替代对机构的信任"从哲学愿景变成了工程现实。
第一部分完