Back to topics

This article does not have an English body yet. Showing the Chinese version below.

区块链基础(上):密码学与数据结构

如果你听说过比特币但一直没搞懂它到底是怎么运作的,这篇文章就是为你写的。我们不谈炒币、不谈行情,只聊技术——区块链最底层的两块基石:密码学数据结构


一、密码学:区块链的数学地基

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 确实在某区块中:

  1. 节点提供 TxB 的哈希 Hash(B)
  2. 加上 "兄弟节点" Hash(A)
  3. 加上路径上的中间节点 Hash(C,D)
  4. 你自己算一遍,看是否等于区块头里的 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 挖矿的完整流程。


本文整理自个人学习笔记,力求用通俗语言讲清核心概念。如有疏漏,欢迎指正。