一把钥匙四种长相:BIP-384 combo() 描述符的迁移使命 图 1
一把钥匙四种长相:BIP-384 combo() 描述符的迁移使命 · 图 1

钱包行业有过一段「同钥不同址」的乱账:同一把私钥,A 钱包给你 P2PKH 地址,B 钱包给你原生隔离见证地址,C 钱包还要再给一个嵌套包装版;等用户换成描述符体系,三个历史地址分属三个模板,导入扫描各扫各的。2021 年 6 月 27 日立项的 BIP-384 就是来收编这段历史的:Pieter Wuille 和 Ava Chow 定义 combo() 描述符,状态 Deployed,依赖 BIP-380,Bitcoin Core 从 0.17 版就实现了它。动机一句话讲清——让从「基于密钥的钱包」迁到「基于描述符的钱包」的路上,一把老钥匙能一次性交代它历史上生成过的所有脚本。

规则短到可以背下来。combo(KEY) 是顶层表达式,吃一个密钥表达式,吐 2 个或 4 个输出脚本。无条件产出的是 P2PK 和 P2PKH——等价于把密钥分别塞进 pk() 和 pkh();如果这把密钥是或含有压缩公钥,再加收 P2WPKH 和 P2SH-P2WPKH——等价于 wpkh() 与 sh(wpkh())。测试向量把账算得很细:一条 WIF 私钥写成的 combo 展开出四条脚本,十六进制依次是 P2PK(21 开头 ac 结尾)、P2PKH(76a9……88ac)、原生隔离见证(0014 开头)、嵌套包装(a914……87);换成非压缩公钥则只剩两条,因为 v0 隔离见证程序要求压缩公钥。带指纹前缀的 xpub、带通配的 xprv 也都给了向量,子密钥 0 与 1 各展开四套。

有两条无效规则值得单独说:combo 只能当顶层,塞进 sh() 或 wsh() 里都非法,把 pkh() 套进 combo 也不合法。道理在于 combo 的职责就是「摊平一个密钥的全部历史形态」,再包一层会让「一个描述符对应一组确定脚本」的描述符公理失效——包装之后到底要产出哪几个脚本、如何编号,规范就没法自洽了。这也解释它为什么不算新脚本类型:combo 生成的每一条脚本都是早就存在的老朋友,任何钱包和浏览器都认得,这正是向后兼容的定义——描述符本身是新的,产物全是旧的。

用迁移视角看它最顺。把 Core 老钱包的默认派生交给 combo(),扫描器一条表达式就能覆盖 1Gen 时代到 1Seg 时代的全部地址空间,导入、备份、审计都只剩一行文本。这也契合描述符家族的总叙事:BIP-380 定语法骨架,381 与 382 收编非隔离与隔离单签,383 管多签,386 管 Taproot,384 专门站在旧钱包的门口当转换器。它 Deployed 而不少同类停在 Draft,原因不在机制巧妙,而在问题真实:每个做大版本迁移的钱包工程都撞见过它。

常见误区有三个。其一,把 combo 当成「能收款四种地址」的魔法:四个脚本是同一段密钥下的四套账本视图,不是四种货币。其二,在非压缩公钥上期待 4 个输出:规范只给 2 个,缺的那两个不是实现 bug 而是 v0 见证规则所定。其三,把 combo 套进 sh() 想着「再来一层」:直接非法;要嵌套形态请写显式的 sh(wpkh(…))。

还要说清它不做什么。combo 不涉及多签与 Taproot:两样都有专属描述符(多签走 mixed 与 sortedmulti,Taproot 走 tr)。它也不承诺任何「未来脚本类型」:将来出现新的标准输出形态,不会自动进 combo 的产物清单,因为它的使命被刻意限定在「旧钱包已经生成过的东西」——扩大产物反而破坏向后兼容的靶心。理解这条边界,就理解了为什么 Core 的迁移工具用 combo 处理历史、用 pkh 或 wpkh 建新钱包。

一条对照账:不用 combo 的迁移工作簿长什么样?pkh 一条表达式、wpkh 一条、sh(wpkh) 一条、p2pk 可能还有一条,四条路径四份备份,漏一条就丢一段历史。combo 把它压成一行,代价是你必须接受「四个输出同属一份表达式」的心智模型——备份该描述符,就同时备份了这四种命运。

快速问答。问:combo() 生成的地址今天推荐用哪个?答:日常收款通常用 P2WPKH 那条,费率低;其余是历史兼容位。问:它跟 walletimportdescriptors 什么关系?答:Core 迁移工具把旧钱包信息转成 combo 表达式再导入。问:非压缩公钥为什么没有隔离见证?答:P2WPKH 的承诺按压缩公钥定义,非压缩密钥不符合这条标准脚本形态,规范对这类密钥只产出两个脚本。

风险提示:本文是钱包机制科普,不构成投资建议;迁移钱包前请离线备份原始种子与旧描述符,任何导入操作先用小额验证余额可完整扫描。