摘要
本文从原理与实现两个角度,讲清比特币密钥体系的每一步:secp256k1 的直观与本质、私钥到公钥的标量乘法、助记词(BIP39)到种子的 PBKDF2 拉伸、以及 BIP32 的分层派生与地址生成流程(从熵到地址)。
目录
- 为什么要讲这些
- 简要回顾:公钥密码学与哈希函数在比特币中的角色
- 椭圆曲线(ECC)与 secp256k1:直观与本质
- 私钥 → 公钥:到底发生了什么
- 从公钥到地址(SHA256、RIPEMD160、Base58Check)
- 助记词(BIP39):如何把随机数变成可读的种子
- HD 钱包与派生(BIP32/BIP44):助记词到无数私钥的桥梁
- 三者之间的关系总结(表格) + 常见问答
- 实用示例:一段从熵到地址的伪代码
- 小结与安全建议
1. 为什么要讲这些
理解私钥、公钥、助记词及它们的生成关系,不只是学术兴趣:
- 决定如何安全备份与恢复钱包;
- 帮助审计 / 实现轻量钱包(或定位密钥相关问题);
- 理解签名、交易验证与密钥泄露的传播路径。
2. 简要回顾:公钥密码学与哈希在比特币中的角色
- 私钥(Private Key):控制资金的根秘密,通常是一个 256-bit 的大整数。
- 公钥(Public Key):由私钥单向计算得到,用于验证签名。
- 地址(Address):公钥经过哈希和编码后的短字符串,便于展示与输入。
- 哈希函数(SHA-256、RIPEMD-160):压缩公钥并提供不可逆性与校验。
这些构成保证了“能花的是能签名的人”,同时地址更便于人类交流。
3. 椭圆曲线(ECC)与 secp256k1:直观与本质
直观说明
比特币使用的曲线 secp256k1 的方程形式为:
[ y^2 = x^3 + 7 ]
但要记住:实际运算是在一个有限域 (\mathbb{F}_p) 上(模一个大素数),因此点集合是离散的。
核心运算是 标量乘法:对基点 (G) 做 (k) 次加法(记作 (Q = k\cdot G))得到公钥点。这个过程是单向的——知道 (Q) 很难反推出 (k)(椭圆曲线离散对数问题 ECDLP)。
secp256k1 的关键要点(概览)
- 曲线方程:
y^2 = x^3 + 7。 - 域为:大素数
p = 2^256 - 2^32 - 977(具体数值由标准给出)。 - 基点
G:曲线上一个固定的生成点,私钥 k 与公钥 Q 的关系是Q = k * G。
注:曲线图在实数域上是连续曲线,但在有限域上是离散点集,直观图主要帮助理解运算规则。
4. 私钥 → 公钥:到底发生了什么
私钥是什么
私钥通常是一个范围在 ([1, n-1]) 内的整数(n 是群的阶,接近 2^256),在钱包里通常以 32 字节二进制保存。
公钥如何计算
公钥是私钥对基点的标量乘法结果:
[ Q = k \cdot G ]
其中 Q 是曲线上的点,包含 x 和 y 两个坐标。该运算是单向的(基于 ECDLP 的假设),因此私钥泄露会导致资金被控制,但仅知道公钥并不能逆算私钥。
压缩公钥与未压缩公钥
- 未压缩公钥格式:
0x04 || x || y(65 字节)。 - 压缩公钥格式:
0x02/0x03 || x(33 字节),用 x 和 y 的奇偶性表示 y 的符号,节省空间。
5. 从公钥到地址(步骤拆解)
以传统 P2PKH(以 1 开头的地址)为例,生成流程:
- 得到公钥字节(压缩或未压缩)。
sha256(pubkey)。ripemd160(sha256(pubkey))—— 得到 20 字节的PubKeyHash。- 在前面加版本字节(主网 P2PKH 为
0x00),对拼接的数据做双 SHA256 并取前 4 字节作为 checksum。 - 将
version + PubKeyHash + checksum做 Base58Check 编码,得到可读地址(以1开头)。
6. 助记词(BIP39):如何把随机数变成可读的种子
三步走
- 生成熵(Entropy):通常为 128 / 160 / 192 / 224 / 256 位(对应 12/15/18/21/24 词)。
- 熵 → 助记词:把熵补上校验位(checksum),分成每组 11 位,映射到 BIP39 词表中的词,得到助记词序列。
- 助记词 → 种子(Seed):用
PBKDF2(HMAC-SHA512),salt = "mnemonic" + passphrase,迭代 2048 次,输出 512-bit(64 字节)的种子。
Seed 是 BIP32 派生主私钥与链码的输入。
注:助记词还可以带一个可选的
passphrase(有些钱包称为额外密码或第 25 个词),这个 passphrase 会被加入 PBKDF2 的 salt 中,大幅改变派生出的种子。
7. HD 钱包与派生(BIP32/BIP44):助记词到无数私钥的桥梁
核心思想
BIP32 定义了层级确定性(HD)密钥:从一个主 seed 生成 master private key + chain code,之后通过 CKD(Child Key Derivation)函数不断派生出子密钥,形成树结构。
- 非 hardened 派生:可以用父公钥加 index 推导子公钥(便于观察/热钱包)。
- Hardened 派生(index >= 2^31):只能用父私钥派生,防止某些信息泄露导致安全问题。
派生函数内部使用 HMAC-SHA512(chain_code, data),输出 512-bit,左右各 256-bit 分别作为子私钥的调整量与新链码。
8. 三者之间的关系
简化流程:
助记词(Mnemonic) --PBKDF2--> Seed (64 bytes) --BIP32--> Master (privkey + chaincode) --派生--> 私钥 k --ECDSA/点乘--> 公钥 Q = k*G --hash--> 地址
| 元素 | 作用 | 是否公开 |
|---|---|---|
| 助记词(BIP39) | 恢复钱包的可读种子 | 不得公开(敏感) |
| 种子(Seed) | 派生主私钥的原料 | 不得公开 |
| 私钥 k | 控制资金 | 最敏感 |
| 公钥 Q | 验签 / 生成地址 | 可公开 |
| 地址 | 收款标识 | 公开 |
9. 常见问答(FAQ,直奔重点)
Q:已知地址能否算回公钥或私钥?
A:地址是公钥的哈希(RIPEMD160(SHA256(pubkey))),哈希不可逆,因此不能从地址直接恢复公钥或私钥。只有当你把某次交易花掉并在交易中公布了公钥时,区块链上才有该地址对应的公钥。
Q:助记词可以被穷举吗?
A:理论上可以,但 12/24 词助记词所对应的熵级和 PBKDF2 的迭代(2048 次)使得穷举在没有其它信息的情况下不可行(现实上不可行)。
Q:压缩公钥和未压缩公钥有什么差别?
A:压缩公钥只保留 x 坐标和 y 的奇偶位(0x02/0x03 || x),节省空间,但对地址生成的哈希输入不同(因此地址会不同)。
10. 实用示例:从熵到地址
说明:下面是伪代码,便于理解流程。生产环境请使用成熟库(libsecp256k1、bip39、bip32 等)并在离线/受控环境下测试。
# 伪代码(逻辑清晰,但非生产级别)
import os, hashlib, hmac
# 1. 生成 128-bit 熵 -> 12 词
entropy = os.urandom(16) # 128 bits
# 2. entropy -> mnemonic (按 BIP39 字典映射,这里用 helper 函数)
mnemonic = entropy_to_mnemonic(entropy) # 返回空格分隔的 12 个单词
# 3. mnemonic -> seed (PBKDF2-HMAC-SHA512, iterations=2048)
salt = ("mnemonic" + (passphrase_or_empty)).encode('utf-8')
seed = pbkdf2_hmac('sha512', mnemonic.encode('utf-8'), salt, 2048, dklen=64)
# 4. seed -> master private key + chain code
I = hmac.new(b"Bitcoin seed", seed, hashlib.sha512).digest()
master_priv = I[:32]
master_chaincode = I[32:]
# 5. 派生第 0 个私钥(简化示意)
child_priv, child_chaincode = CKD_priv(master_priv, master_chaincode, index=0)
# 6. 私钥 -> 公钥(椭圆曲线标量乘)
pubkey = scalar_multiply_G(child_priv)
# 7. 公钥 -> 地址(P2PKH)
sha = hashlib.sha256(pubkey).digest()
rip = ripemd160(sha)
payload = b'\x00' + rip
checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
address = base58_encode(payload + checksum)
print(mnemonic)
print(address)
11. 小结与安全建议
- 助记词 = 钱包:任何人拿到助记词或主私钥就能恢复并花掉资产。务必离线备份,避免拍照上传云端。
- Passphrase(可选):可以显著提升安全性,但千万不要忘记。
- 使用成熟库与硬件钱包:不要在生产环境自己实现加密原语;仅在受控环境中实现学习代码。
- 最小化公钥/地址的暴露:地址通常可公开,但尽量避免在不必要的场合泄露公钥。