密码学 31:HD 钱包和助记词——备份如何恢复很多密钥
钱包第一次显示一串助记词,随后能生成几百个收款地址。备份这串词以后,换一台设备却只看见零个余额:是“签名坏了”吗?更可能是助记词、额外 passphrase、账户派生路径、脚本类型或网络任一项不同。钱包不是一把私钥;它管理密钥、不同脚本或账户的派生方式与恢复所需信息。把“备份助记词”误读成“地址从此只有一种确定解释”,恢复时会产生令人困惑但可避免的结果。
从输入熵到一棵可复现的派生树
BIP 39 先将一定熵、校验位编码为指定词表中的词。词本身只是人可抄录的表示,不是对秘密的加密;读到有效助记词的人也可能恢复签名权。下一步将经过 NFKD 规范化的助记词作为输入、"mnemonic" || NFKD(passphrase) 作为 salt,经 2048 次 PBKDF2-HMAC-SHA512 得到 64 字节 seed。这个 passphrase 不是帮助记忆的标签:换一个字符即得到另一棵树;没有独立的“正确口令标记”帮助钱包判断你输错了哪一个。
BIP 32 再对 seed 做 HMAC-SHA512(key="Bitcoin seed", data=seed),前 32 字节候选主私钥、后 32 字节 chain code。通过特定索引派生子节点时,HMAC 的输入取决于索引是否硬化:普通子节点使用父压缩公钥、索引与父 chain code,硬化子节点使用 0x00 || 父私钥 || 索引 与父 chain code。所得左半作为曲线上对私钥或公钥的 tweak,右半成为子 chain code;还必须拒绝/跳过规范说明的极少数无效索引。HKDF 的“用途分离”直觉能帮助识别每步数据变化,但不要把 BIP 32 的 HMAC 输入和输出误称为 TLS 的 HKDF。
1 | |
持有扩展公钥 xpub(公钥加 chain code 等元信息)的人通常可以沿普通子索引推导子公钥,适合只观察地址的组件;这不是任意路径上的签名权。但如果父 xpub 与对应普通子私钥一起泄露,可以从 HMAC 的公开父公钥及链码重新求出 tweak,再减回父私钥。硬化派生切断了这一“从公开父节点计算同一个 tweak”的路径,代价是观察者不能单靠父 xpub 导出硬化子节点。把 xpub 当作毫无隐私代价的公开标识同样危险:它能泄漏一组相关地址与交易线索。
对照规范向量,不冒充钱包恢复
examples/cryptography/31_wallet_derivation.py 用已公开的 BIP 32 seed 000102...0f 核对主密钥向量前缀,分别从父私钥、父公钥推导普通子节点序号 7:使用真实 secp256k1 库,公钥和 chain code 应相同;硬化索引从公钥派生则直接拒绝。BIP 39 的公开测试词句 abandon ×11 + about 与 passphrase TREZOR 用 PBKDF2 求出的 seed 前缀应为 c55257c360c07c72...,把 passphrase 留空得到另一个 seed。这些词句和种子完全公开,不可接收真实资产。
先按仓库内 examples/cryptography/README.md 完成环境准备;以下命令从仓库根目录执行。
1 | |
三项测试通过只说明所用派生子集与指定公开向量、相关性测试相符。脚本没有词表和校验位处理,没有完整 BIP 32 xprv/xpub 序列化、无效索引自动跳过、账户发现、恢复扫描或钱包设备互通;Bitcoin Core regtest 的实际导入备份均 NOT_RUN。生产恢复需要冻结确切的路径、脚本、网络、额外 passphrase 和钱包实现,不能只凭这个教学片段去保护有价值资金。
经 HTTPS RPC 提交交易的场景里,HD 树负责钱包保存、恢复并选定交易签名密钥,HTTPS 保护钱包到服务的一段通道。备份成功既不会核实 RPC 身份,也不能证明交易有效、已打包或已支付现实订单。
练习及答案
画图题: 画出“同一句助记词,不同 passphrase”及“同一 seed,不同派生路径”两种分叉。观察设备只有账户级 xpub 时,为什么看得见某些新地址却签不了名?
答案: passphrase 在 PBKDF2 的 salt 中,改它得到不同 seed 和整棵树。seed 一样但路径索引或硬化步骤不同,最终公钥通常不同。观察设备有父扩展公钥和 chain code,可以走允许的普通子公钥分支;没有私钥不能给交易签名,也不能越过该节点去推导硬化子私钥。脚本和网络不同还可能让相同公钥对应不同地址。
实验变更题: 把测试的 "TREZOR" 改成 "trezor",seed 向量会怎样?再把普通子序号 7 改成硬化 2**31+7,child_public 应成功吗?
答案: 规范化不会合并大小写;PBKDF2 的 salt 改变,原公开向量断言失败。硬化子派生需要父私钥,公开子派生必须抛 ValueError;若改代码让它凭 xpub 返回某个字节串,不等于规范 BIP 32 的那个硬化子节点。
资料与衔接
- BIP 39:Mnemonic code for generating deterministic keys;BIP 32:Hierarchical Deterministic Wallets。
- 26:私钥、公钥、地址与钱包 · 28:Ethereum 交易授权;Ethereum 路径另按钱包/链标准核对,不把本章 BIP 32 教学索引误称为跨链默认路径。






