协议演进 / BIP/比特币改进提案 / BIP-32
BIP-32
从一个种子派生出一整棵密钥树:钱包只需备份一次,就可以按账户与用途分层生成无数地址,还能只分享某一支的公钥而不交出花费权。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-32 |
|---|---|
| 标题 | Hierarchical Deterministic Wallets |
| 作者 | Pieter Wuille <[email protected]> |
| 指定日期 | 2012-02-11 |
| 层级 | Applications(应用) |
| 类型 | Informational(信息类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/32 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki |
二、放在哪一族
BIP-32 是确定性钱包族的地基。它定义了“种子 → 密钥树”这套派生机制本身,后来的一系列文档都建在它上面:
BIP-39:把种子写成助记词,让人能抄写与口述
BIP-43:给树的第一层加“用途”字段
BIP-44:多账户层级结构,规定币种、账户、内外部链的固定路径
再往后还有 BIP-49、BIP-84、BIP-86 等按地址类型分工的派生方案,用的都是 BIP-32 的树与扩展密钥。
文档分两部分:第一部分是密钥派生系统本身;第二部分是在这棵树上搭出的默认钱包结构。第二部分是建议性的,第一部分才是互通的关键。
三、它要解决什么
当时的参考客户端使用随机生成的密钥:为了避免每笔交易后都重新备份,默认预存 100 个备用密钥放进密钥池。即便如此,这类钱包仍有三个硬伤:
- 备份要反复做:随机密钥不断新增,旧备份随时过期;
- 不能安全地跨系统共用:钱包不打算被多台设备同时使用;用加密功能把私钥藏起来后,“阉割版”钱包连新公钥(新地址)都生成不了;
- 分享只能全有或全无:普通确定性钱包通常只有一条密钥链,想分享就得分享整条链,没法只交出其中一部分。
原文举的例子是网店:商家希望让网站服务器为每笔订单、每位顾客生成新收款地址,但绝不能把能花钱的私钥放在服务器上。用椭圆曲线数学,可以只给服务器算公钥的能力;再加上分层结构,服务器拿到的只是“对外收款”那一支,连找零地址那一支都看不到。
四、规则本身
4.1 扩展密钥:密钥加链码
每个密钥都附带额外的 256 位熵,称为链码(chain code,32 字节)。私钥加链码记作扩展私钥 (k, c),公钥加链码记作扩展公钥 (K, c),其中 K 是由 k 算出的公钥。对应的扩展公私钥共用同一条链码。
每个扩展密钥有 2 的 31 次方个普通子密钥和同样数量的硬化(hardened)子密钥:普通子密钥用索引 0 到 2 的 31 次方减 1,硬化子密钥用 2 的 31 次方到 2 的 32 次方减 1,写作 i 加下标 H。
4.2 子密钥派生(CKD)
派生用 HMAC-SHA512,链码作密钥:
- 私钥派生私钥(CKDpriv):硬化子密钥的数据是
0x00 || 父私钥 || 索引,普通子密钥的数据是父公钥 || 索引。输出的左半部分加到父私钥上得到子私钥,右半部分作子链码; - 公钥派生公钥(CKDpub):只对普通子密钥有定义,硬化子密钥直接失败。输出左半部分对应的点加到父公钥上,右半部分作子链码;
- 私钥可转公钥:把扩展私钥“阉割”(neutered)成扩展公钥,链码不变,花费能力被去掉;
- 公钥推不出私钥:这一方向在数学上不可行,分层分享的安全性正建立于此。
逐级派生就得到密钥树,路径写作如 m/3H/2/5(m 为主密钥,M 为其扩展公钥版本)。叶子节点是实际使用的密钥,中间节点代表由它派生出的整组后代。
4.3 主密钥怎样从种子来
先取一段 128 到 512 位的种子(原文建议 256 位),计算 HMAC-SHA512(Key = "Bitcoin seed", Data = 种子),左半部分作主私钥,右半部分作主链码。
4.4 序列化:xprv 与 xpub
扩展密钥序列化为 78 字节:4 字节版本字节(主网公钥 0x0488B21E、私钥 0x0488ADE4;测试网另有取值)、1 字节深度、4 字节父密钥指纹(取公钥 Hash160 的前 32 位)、4 字节子编号、32 字节链码、33 字节密钥数据。再加 4 字节双重 SHA-256 校验和并做 Base58 编码,得到恰好 111 个字符的字符串,主网上分别以 xprv、xpub 开头。
4.5 默认钱包结构
钱包按账户组织,默认账户编号为 0。每个账户有两条链:外部链用于生成对外收款地址,内部链用于找零等不必对外沟通的用途。路径约定为:m/iH/0/k 是账户 i 外部链的第 k 个密钥对,m/iH/1/k 是内部链的第 k 个。
原文列出的典型用法包括:共享主扩展私钥实现整钱包共享;把各账户的扩展公钥交给审计方,让其看到全部收付而碰不到任何私钥;总部用主密钥统看各分支办公室的钱包;把某账户外部链的扩展公钥当作“超级地址”,反复收款又不易被关联;以及只给不安全的电商服务器一支外部链扩展公钥——服务器被攻破也偷不走钱。
4.6 安全要点
原文专门强调一条反直觉的性质:父扩展公钥加上任意一个由它派生的普通(非硬化)子私钥,就等价于知道了父扩展私钥,进而能推出该父密钥的全部后代私钥。因此扩展公钥必须比普通公钥更小心地保管,账户层要用硬化派生——这样单个账户或更下层私钥的泄露,才不会危及主密钥和其他账户。
五、谁必须动
普通持币人:备份方式变了:从“反复备份随机密钥池”变成“保管好一个种子 / 主密钥”。种子在,整棵树都能重建;种子丢了或泄露了,整棵树都受影响。
钱包开发者:要实现扩展密钥、CKD 派生、硬化与普通索引、序列化导入导出,并至少能导入一个扩展公钥或私钥、访问其直接后代。默认钱包结构是建议而非强制,但原文鼓励照做以保持兼容。
商家与服务器运营方:可以在服务器上只部署扩展公钥生成收款地址,私钥离线保管——这是本 BIP 最早描绘、后来被广泛采用的部署方式。
共识层与全节点:完全不动。BIP-32 是纯钱包侧的密钥管理方案,链上看到的仍是普通公钥与签名,节点无从也无需知道某个地址出自哪棵树。
六、现在算不算数,以及一个常见误读
状态为 Deployed,类型虽标为 Informational(信息类),其派生与序列化规则事实上已成为钱包互通的通用标准:xpub / xprv、路径记法、硬化标记,今天仍是各类钱包与工具的共同语言。具体账户结构由 BIP-44 等后续文档细化,种子的人类可读形式由 BIP-39 承担。
常见误读:
“xpub 只是公钥,公开它没有任何风险,随便发给谁都行。”
不对。原文的安全一节写得很明确:扩展公钥泄露首先是隐私泄露——对方能推出该支全部地址,看清你的收付全貌;更危险的是,若对方再拿到该支下任意一个普通子私钥,就能反推出父扩展私钥,接管整支密钥。xpub 要按“半个私钥”来保管,而不是按普通收款地址来随手分发。
七、延伸
- 阅读版:https://bips.dev/32
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
- 相关:BIP-39 助记码、BIP-43 用途字段、BIP-44 多账户层级结构
- 仓库总目录:https://github.com/bitcoin/bips
