同一组公钥为什么会开出不同的多签地址:BIP67 的排序约定 图 1
同一组公钥为什么会开出不同的多签地址:BIP67 的排序约定 · 图 1

三位合伙人各交一把公钥,约定”任意两位”即可花钱——听起来地址唯一。但若有人把公钥顺序排成 A、B、C,另一人排成 B、A、C,两边算出的 P2SH 地址不同,各自还会坚持自己的是对的。BIP67 要消灭的就是这种”同配置多地址”:把多签脚本里的公钥排序写死成字典序,让一份配置只对应一个脚本、一个地址。本文拆解排列从哪来、约定怎么定、今天的多签工具为什么仍要提它。

排列问题的规模

P2SH 多签的重建脚本结构是固定的:门限数字、n 把公钥、总数数字、CHECKMULTISIG。规范当年没规定公钥的排列顺序,于是 n 把钥匙理论上有 n 的全排列种脚本写法——五把钥匙就是一百二十种合法脚本、一百二十个可收款地址。现实里常见的是钱包实现差异:有的按用户录入顺序、有的按派生路径顺序、有的干脆按字面字节排序。后果分三级:轻则同一多签在两家服务里显示为两个地址、对账报表分裂;重则签名方与验证方各自重建脚本导致验签失败;最麻烦的是恢复场景——钱包种子完好却因为当年录钥匙的顺序无从复现,资金”找不回地址”。

同一组公钥为什么会开出不同的多签地址:BIP67 的排序约定 图 2
同一组公钥为什么会开出不同的多签地址:BIP67 的排序约定 · 图 2

BIP67 的约定长什么样

BIP67(2015 年 2 月立项,作者 Thomas Kerin 等三人,状态 Complete)的规则朴素:先确保每把公钥以压缩格式交齐——收到未压缩密钥应被解读为”对方实现不兼容”的信号——再按字节的字典序升序排列,排进标准的门限加公钥列表加 CHECKMULTISIG 脚本,最后按 BIP16 哈希出 P2SH 地址。共识层并不强制这套约定:P2SH 付款时脚本尚未揭示,想在链上强制就得硬分叉,BIP 明确放弃这条路。它因此是纯粹的钱包间协调标准——各家按同一排序函数重建脚本,排列歧义就消失。标准落地后主流多签与硬件签名器陆续把它当默认行为,录入顺序影响地址的时代基本结束。

隔离见证时代的余波

进入原生隔离见证与 Taproot 后,多签脚本进 witness 或叶表,排序约定依然有效——脚本结构不变,歧义来源就不变。更现代的答案是输出描述符:把 m 加 n 配置、派生路径与排序规则一次性序列化,两个钱包交换描述符字符串即可保证从脚本到地址完全一致,排除了所有”先录哪把钥匙”的隐藏状态。可以说 BIP67 解决第一代问题,描述符解决第二代问题;审计多签配置时,先看描述符、再看公钥顺序是否字典序,这两步能解释绝大多数”为什么地址对不上”。

一个直觉算术

排列数随钥匙数跳升:三把钥匙六种写法、五把一百二十种、七把五千零四十种。多签参与方越多、代持周期越长,地址分裂造成的损失越接近复利——每次对账都要多一层”哪个才是真地址”的确认。排序标准把这一层成本清零,这就是为什么一个不碰共识的小小 BIP 能被多签服务商集体采纳。顺手自测也很轻量:拿三把测试公钥让两家工具各生成地址,一致即双方都守约;不一致,导出来看脚本里公钥顺序谁排错了——排序错误永远是显性的,没有隐藏状态,这正是字典序约定想要的效果。

快速问答

问:BIP67 之后旧地址还能花吗? 答:能。脚本里的顺序只是没统一,钱在任何合法排列脚本上都可花,BIP67 只统一了”新建时怎么排”。

问:怎么检查钱包是否遵守? 答:导出配置脚本比对公钥顺序,或直接比较两家工具从同一组钥匙生成的地址。

问:Taproot 多签还需要排序吗? 答:脚本路径里的分支仍应遵守同一排序,密钥路径聚合方案则把顺序问题交给参与方协议。

风险提示:本文解释地址与脚本标准,不构成投资建议。多签上线前请用小额资金完成全流程演练。