协议演进 / BIP/比特币改进提案 / BIP-138
BIP-138
为输出脚本描述符、钱包策略等非种子钱包数据定紧凑加密备份格式:密钥由描述符中的公钥导出,备份可存到不可信介质而不泄露地址与脚本结构,且载荷不得含任何私钥材料。本 BIP 目前处于草案状态。
一、档案卡
| 编号 | BIP-138 |
|---|---|
| 标题 | Compact Encryption Scheme for Non-seed Wallet Data |
| 作者 | Pyth <[email protected]> |
| 指定日期 | 2026-05-11 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Draft(草案) |
| 依赖文档 | Requires: BIP-32, BIP-340, BIP-380, BIP-388, BIP-389, BIP-390 |
| 阅读版 | https://bips.dev/138 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0138.md |
二、放在哪一族
钱包描述符与备份族。BIP-138 档案头明确写了它依赖的一串文档,读它要先认清这条链:
BIP-32:分层确定性钱包,xpub 与派生路径的来源。
BIP-340:Schnorr 签名。本 BIP 借用它的带标签哈希(tagged hash)构造来派生秘密,并使用 x-only 公钥形式。
BIP-380:输出脚本描述符。本 BIP 加密备份的首要对象。
BIP-388:钱包策略。另一首要对象;BIP-389、BIP-390 同列在依赖中,其中 BIP-390 的 musig() 表达式在本 BIP 的密钥规则中有专门处理。
范围上它还顺带覆盖:标签数据见 BIP-329 一类用途,以及 BIP-139 一类钱包备份元数据——原文说方案为描述符与策略而设计,但同样适用于标签与备份元数据。
这一族共同的焦虑是同一件事:种子之外,还有一份“说明你的币在哪”的数据,丢了或泄露了都出事。
三、它要解决什么
3.1 丢描述符,几乎和丢种子一样致命
原文开门见山:种子让你能签名,描述符把你映射到你的币。丢失钱包描述符或钱包策略,几乎和丢种子本身一样灾难性。
对多签或 Miniscript 钱包,光有钥匙不够:没有描述符,就重构不出脚本。原文还提醒一个不直观的风险:某些多签设计本可在丢一把种子时仍保住币,但若那把种子的公钥也随之丢失,币照样可能变得不可达。
3.2 离线存太长,在线存泄露
描述符离线保管有两个实际障碍:
- 描述符可能远比 12 或 24 个助记词长,纸质与钢板备份变得不实际、易出错;U 盘等离线数字介质会随时间退化,也难扛水火;
- 手机与云盘解决了长度问题,却暴露钱包结构:明文描述符会泄露公钥与脚本细节,云存储往往未加密,即便加密,其实现不透明、安全性又归结为能访问云的最弱设备,每多一份拷贝就多一份攻击面。
3.3 目标性质
BIP-138 要的是一份加密、紧凑的备份格式,并列明期望性质:
- 加密:可安全存放在不可信的云服务商或备份服务处;
- 访问受控:只有指定共同签名人能用其 xpub 解密,且不能用链上已 revealed 的公钥解密;
- 易实现:不需要复杂工具或库,也不要求访问私钥材料——安全的签名系统本就不会交出私钥;
- 厂商中立:可与任何硬件签名器配合。
范围红线先划清:载荷在加密前必须移除一切私钥材料。正因为解密靠的是公钥材料,这套方案不适合存私钥。
四、规则本身
4.1 秘密如何从公钥派生
取载荷中全部描述符与策略集合、全部内容项里出现的不同公钥 p1 到 pn,按字典序排序。方案对任意 n 不小于 1 都成立,包括单签描述符(n=1)。每个 pi 是某个允许的密钥表达式的、经 x-only 归一化的根公钥。
再按 BIP-340 的带标签哈希构造计算:
- 总秘密 s = tagged_hash(“BIP138_DECRYPTION_SECRET”, p1 | p2 | … | pn);
- 个体秘密种子 si = tagged_hash(“BIP138_INDIVIDUAL_SECRET”, pi);
- 存入备份的个体项 ci = s 与 si 的异或(XOR)。
两个不同的域分隔标签保证 s 不等于 si,ci 因此永不为全零串。
解密时,持有某个公钥 p 的人算出自己的 si,逐个与备份中的个体项异或尝试重构 s,能成功解密,当且仅当 p 确实是描述符或钱包策略中的钥匙之一。不需要任何额外口令或秘密——任何钥匙持有人都能打开,这正是“密钥由公钥导出”的含义。
4.2 哪些钥匙不许用
这是原文着墨最重的防护:若某把钥匙已经在链上公开,用它导出的秘密任何人都能重算,备份等于明文。因此:
musig() 之外,只有带尾随派生步或通配符的扩展公钥型表达式才计入密钥集合;字面公钥与裸 xpub 一律排除,因为它们的根公钥正是链上花费时出现的公钥,观察一次花费即可重算总秘密。固定派生(如 xpub…/0/5)允许,因链上钥匙已与根不同。
musig() 内部参与者可用带或不带尾随派生的 xpub(聚合后的链上钥匙不泄露单个参与者钥匙),但字面公钥参与者仍排除;加密时用各参与者的 xpub 根,而非聚合钥匙。
还必须排除 x 坐标等于 BIP-341 NUMS 点的那把钥匙;若某候选根在载荷任一描述符或已解析策略中又以字面钥匙或裸 xpub 形式在 musig() 外出现,也必须排除。
实现必须:排除一切不合格形式;若排除后集合为空,必须拒绝编码备份;必须让用户知道每个被排除的表达式与候选根,因为其持有人可能无法用那把钥匙解密。
原文另有一条使用警告:某些单签钱包的桌面应用会把账户 xpub 发给服务器,这类 xpub 若被复用到多签描述符中,服务器就能解密该多签的每一份备份;用户应使用从未发给这类服务器的账户(如 BIP-48 或 BIP-87 账户)来组多签。
4.3 加密与编码格式
加密算法用 CHACHA20_POLY1305(RFC 8439),96 位随机 nonce 加 128 位认证标签,附加认证数据为空;nonce 不得全零,若随机源给出全零必须重取。原文注脚说明选它的理由:它已用于 Bitcoin Core(如 BIP-324),库支持广、无硬件加速时软件性能也好,适合硬件钱包与嵌入式设备。
编码后的备份依次为:MAGIC(6 字节 ASCII “BIP138”)、VERSION(1 字节,现为 0x01)、DERIVATION_PATHS(可选,帮助用非通用路径恢复;实现可先自动尝试一组原文列明的常见路径)、INDIVIDUAL_SECRETS、ENCRYPTION(1 字节算法标识,0x01 表示 CHACHA20_POLY1305,0x00 保留)、ENCRYPTED_PAYLOAD。
两处刻意的隐私设计:
个体秘密不带指纹明文,以免直接泄露描述符参与者信息;编码方应追加随机诱饵个体项,把总数向上凑到 5、10、20 等翻倍桶(上限 255),掩盖真实钥匙数。解码方不区分真假,逐个试到能解密为止。
可变载荷建议填充:把载荷零填充到以 10 KiB 为起点、每次乘 5/4 的桶大小,使备份大小的变化不泄露钱包活动;静态载荷(如描述符、策略)则无须填充。填充位于密文之内,解析者看到的长度只是填充后的长度。
载荷本身由一个或多个内容项组成,每项带内容类型、长度与内容;类型 0x01 表示其后按 BIP 编号指明格式(如 0x017c 即 BIP-380 描述符备份)。空载荷必须拒绝。
五、谁必须动
普通持币人:主要是多签、Miniscript 等复杂钱包的用户。要理解“种子备份之外还有描述符备份”,并按钱包提示把加密备份分散存放;不要自行往载荷里塞私钥。
钱包开发者:这是主要实现方。要实现密钥筛选与排除规则、带标签哈希派生、ChaCha20-Poly1305 加解密、诱饵与填充、常见派生路径的自动尝试与失败警告,并把被排除的钥匙明确告知用户。
全节点与矿工:无须动。本 BIP 是钱包本地的备份格式,与链上验证无关。
共识层:不动。原文没有提出任何共识规则。
六、现在算不算数,以及一个常见误读
状态为 Draft(草案),原文版本字段为 0.1.3。草案意味着格式仍可能调整,钱包是否采纳、采纳哪一版,要看各实现自己的选择;本页不预判它会成为定稿,也不能把“草案里写了”当作“行业已通行”。
它的当前意义在于把一个长期被各钱包各做各的问题写成了可讨论的统一草稿:加密对象、密钥来源、排除规则、诱饵与填充都给出了具体做法,供实现者对照与评审。
常见误读:
“备份既然加密了,把私钥一起塞进去存云上更省事。”
正好相反,这是原文明令禁止的用法:载荷在加密前必须移除一切私钥材料。因为解密能力来自公钥集合的派生,任何一位钥匙持有人都能打开备份;私钥放进去,等于把私钥交给每一个共同签名人可达的解密路径,方案的安全假设当场失效。
七、延伸
- 阅读版:https://bips.dev/138
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0138.md
- 相关:BIP-32 分层确定性钱包、BIP-340 Schnorr 签名、BIP-380 输出脚本描述符、BIP-388 钱包策略、BIP-389、BIP-390
- 仓库总目录:https://github.com/bitcoin/bips
