区块链基础(上):密码学与数据结构
如果你听说过比特币但一直没搞懂它到底是怎么运作的,这篇文章就是为你写的。我们不谈炒币、不谈行情,只聊技术——区块链最底层的两块基石:密码学和数据结构。
一、密码学:区块链的数学地基
1.1 加密哈希函数
区块链的核心组件是加密哈希函数(Cryptographic Hash Function)。比特币用的是 SHA-256(Secure Hash Algorithm,256位输出)。
一个合格的加密哈希函数需要满足三个性质:
抗碰撞性(Collision Resistance)
输入可以是任意长度的任意数据,输出永远是固定长度(SHA-256 输出 256 位)。理论上,输入空间无穷大而输出空间有限(2^256 种可能),碰撞必然存在。但关键在于——你找不到它。
以当前算力,暴力搜索一个 SHA-256 碰撞需要的时间比宇宙年龄还长。所以实际上,H(x) = H(y) 意味着 x = y,哈希值就是数据的"指纹"。
隐匿性(Hiding)
给定哈希值 H(x),无法反推出 x。这有一个经典应用场景——数字承诺(Digital Commitment):
你想预测一场比赛结果,但不能提前公开(怕影响选手)。你可以先把"预测结果 + 一段随机数"的哈希值公开。比赛结束后,你再公布原文,大家一验哈希就知道你没有偷偷改过预测。
那如果输入空间很小(比如"正面/反面"只有2种可能),别人可以穷举所有输入算出所有哈希,然后反查。解决办法很简单——拼接一个随机数,把输入空间"撑大"。
Puzzle Friendly(谜题友好)
这是比特币特别需要的性质:即使你知道目标,除了暴力搜索,没有捷径。
挖矿的本质是找一个随机数 nonce——它是区块头(Block Header)中的一个 32 位字段。矿工把 nonce 和其他区块头字段拼在一起做 SHA-256:
H(version || prev_hash || merkle_root || timestamp || target || nonce) ≤ target
其中 || 表示字节拼接,target 是难度目标(值越小难度越大)。矿工从 0 开始不断递增 nonce 做哈希,看结果是否 ≤ target。如果 32 位 nonce(约 43 亿种可能)全试完还没找到,就调整 merkle_root(修改 coinbase 交易或交易列表),重新来一轮。
SHA-256 的输出完全不可预测——你改一个比特的输入,输出就面目全非。所以没有任何取巧的办法,只能一个一个试。寻找 nonce 极其困难,验证却只需一次哈希——这就是工作量证明(Proof of Work)的核心。
比特币网络每 2016 个区块(约两周)自动调整一次 target,使全网平均出块时间稳定在 10 分钟。
1.2 公钥密码体系
传统银行开户,你得带着身份证去柜台。比特币的世界里,你只需要在本地生成一对密钥——公钥和私钥。
这是非对称加密的核心思想:
- 公钥 → 加密用、接收转账用(可以公开,相当于你的银行账号)
- 私钥 → 解密用、签名用(死也不能给别人,相当于你的银行密码)
别人用你的公钥加密一条消息,只有你的私钥能解开——这解决了对称加密中"如何安全传递密钥"的难题。
但还有一个问题:怎么证明这条消息确实是你发的? 这就要用到数字签名:
- 签名:用私钥对消息签名
- 验证:别人用你的公钥验证签名
别人可以验证签名的有效性,但无法伪造你的签名。比特币的每一笔转账,本质上就是用你的私钥对交易内容签名,全网节点用你的公钥验证。
关键细节:比特币生成私钥时,必须使用密码学安全的随机源(比如基于物理噪声的硬件随机数生成器,或混合系统熵+键盘输入时间等),否则私钥可能被他人推测出来。
二、数据结构:区块链的骨架
密码学提供了"不可伪造"和"不可抵赖",数据结构提供了"不可篡改"和"可验证"。
2.1 哈希指针
普通指针存储的是内存地址。哈希指针存储的是数据的哈希值——它不仅指向数据的位置,还能验证数据是否被篡改。
区块链就是由哈希指针串起来的链表:
[区块0] ← [区块1] ← [区块2] ← [区块3] ← ...
↑ ↑ ↑ ↑
创世区块 prev_hash prev_hash prev_hash
指向区块0 指向区块1 指向区块2
每个区块的头部存着前一个区块的哈希值(称为 prev_hash)。如果有人篡改了区块2的内容,区块2的哈希就变了,区块3里存的 prev_hash 就对不上了。要掩盖这个篡改,就得同时修改区块3、区块4……一直改到最新区块。这在算力上是不可行的。
第一个区块叫创世区块(Genesis Block),它没有前驱,"prev_hash" 是一个约定值(比特币是全是0)。
2.2 Merkle 树
如果区块链只是一个链表,那要验证某笔交易是否在一个区块里,就得把整个区块的几百笔交易全部下载下来——这对手机钱包这种轻节点来说不可接受。
Merkle 树解决了这个问题。它和二叉树的区别在于:用哈希指针代替了普通指针。
结构如下:
Root Hash (存在区块头里)
/ \
Hash(A,B) Hash(C,D)
/ \ / \
Hash(A) Hash(B) Hash(C) Hash(D)
| | | |
TxA TxB TxC TxD
- 叶子节点:每笔交易的数据
- 中间节点:两个子节点哈希值的拼接再哈希
- 根节点:存在区块头(Block Header)里
注意:比特币的 Merkle 树不是严格的二叉树——如果某一层节点数为奇数,会复制最后一个节点来凑成偶数。
**Merkle Proof(默克尔证明)**是 Merkle 树的杀手锏。假设你要验证 TxB 确实在某区块中:
- 节点提供 TxB 的哈希 Hash(B)
- 加上 "兄弟节点" Hash(A)
- 加上路径上的中间节点 Hash(C,D)
- 你自己算一遍,看是否等于区块头里的 Root Hash
你只需要 O(log n) 个哈希值(而不是整个区块的所有交易),就能验证一笔交易。这就是为什么轻节点(只存区块头,不存交易列表)也能独立验证支付。
2.3 区块结构
每个区块分成两部分:
| 部分 | 内容 | 存在哪里 |
|---|---|---|
| 区块头(Block Header) | 版本号、prev_hash、Merkle Root、时间戳、难度目标、nonce | 全节点和轻节点都有 |
| 区块体(Block Body) | 交易列表 | 只有全节点存 |
这引出了两种节点:
- 全节点(Full Node / Fully Validating Node):存完整的区块链数据,独立验证每笔交易。是网络的"脊梁"。
- 轻节点(Light Node / SPV Node):只存区块头。依赖全节点提供 Merkle Proof 来验证交易。手机钱包基本都是轻节点。
2.4 哈希指针的"适用范围"
理论上,哈希指针可以构造任何无环的数据结构——链表、树、DAG 都行。但绝对不能用于有环结构,因为会产生循环依赖:A 的哈希依赖 B,B 的哈希又依赖 A,死锁。
小结
这一篇我们讲了区块链的"材料":
- 密码学提供了不可伪造(签名)、不可抵赖(哈希承诺)、工作量证明(puzzle friendly)的数学保证
- 哈希指针 + Merkle 树构成了不可篡改的链式数据结构,同时支持高效的轻量级验证
下一篇我们把这些零件组装起来,看看比特币这条"链"到底是怎么跑起来的——交易脚本、共识协议、以及 PoW 挖矿的完整流程。
本文整理自个人学习笔记,力求用通俗语言讲清核心概念。如有疏漏,欢迎指正。