协议演进 / BIP/比特币改进提案 / BIP-67
BIP-67
规定多签 P2SH 的公钥必须用压缩形式并按二进制字典序排列,使同一组公钥与签名门限永远生成同一个赎回脚本与地址。本 BIP 目前处于已完成状态。
一、档案卡
| 编号 | BIP-67 |
|---|---|
| 标题 | Deterministic Pay-to-script-hash multi-signature addresses through public key sorting |
| 作者 | Thomas Kerin <[email protected]>, Jean-Pierre Rupp <[email protected]>, Ruben de Vries <[email protected]> |
| 指定日期 | 2015-02-08 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Complete(已完成) |
| 阅读版 | https://bips.dev/67 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki |
二、放在哪一族
BIP-67 是多签与 P2SH 族里管“同一个账户该有同一个地址”的那一份。
链条是这样的:BIP-11 把 M-of-N 多签定为标准交易;BIP-16(Pay to Script Hash)定义了多签的 P2SH 形态,花费成本由接收方以赎回脚本承担。但 BIP-16 的赎回脚本并不规定公钥的顺序与编码——脚本不同,哈希出的 P2SH 地址就不同。BIP-67 补的正是这一块:给公钥排一个唯一的序。
原文的用法一节还列了 BIP-45(确定性 P2SH 多签钱包结构)作为采用方,以及 Bitcore、Haskoin、Armory、BitcoinJ 等实现对排序函数的采用。
三、它要解决什么
对同一组公钥、同一个所需签名数,赎回脚本里公钥的每一种排列(再乘以压缩 / 非压缩两种编码的差别)都能构成一个不同的标准赎回脚本,各有自己单独的 P2SH 地址。一个多签“账户”因此没有一个规范地址。
这带来实际麻烦:
- 同一组人共管的账户,在不同钱包里生成出不同地址,对账与识别都困难;
- 特别是多签分层确定性(HD)钱包:本来只需共享“所需签名数 + 各参与方的主公钥”就应能各自独立生成同一批地址,排序不统一,这个最小状态就立不住;
- 许多钱包服务商用 2-of-3 方案(用户自存一把备用钥匙、日常用一把、服务商联签一把),若排序成为通行标准,用户在服务商之外也能由第三方协助恢复钱包,不被服务商绑定。
原文同时指出,当时多数网页钱包还不支持跨服务组建多签账户;能确保跨实现兼容的约定,正是为了让这类互通更容易达成。
四、规则本身
4.1 三步
第一步,统一编码。 确保拿到的每个公钥都是压缩形式:
022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da
03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9
021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18
第二步,按二进制表示做字典序排序。 上例排序后为:
021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18
022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da
03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9
第三步,组装赎回脚本并哈希。 把排好序的公钥放进标准多签赎回脚本,再按 BIP-16 哈希得到 P2SH 地址:
OP_2 <排序后公钥 1> <排序后公钥 2> <排序后公钥 3> OP_3 OP_CHECKMULTISIG
→ 3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba
原文附有四组测试向量(含一组取自 Bitcore),向量里的所需签名数均为 2,可据此核对实现是否排对。
4.2 兼容性条款
- 非压缩公钥与本规范不兼容。 合规实现不应自动把公钥压缩;从某个多签参与方收到非压缩公钥,应理解为对方使用的是不兼容的实现;
- 无法在网络层面强制。 P2SH 地址不透露所收资金脚本的任何信息,节点无从核查排序;而且真要强制会构成硬分叉。所以它只能是钱包之间的约定;
- 不合规实现与严格合规钱包之间会有兼容问题;采用本标准的实现之间则可跨实现互通;
- 一群人里只要有人不合规,就可能出现某参与方推导出的地址不被其他参与方认作共同账户地址的情形。
五、谁必须动
普通持币人:不必动节点或软件规则。使用多签产品时,地址由钱包按本规范生成即可。
钱包开发者:这是主要受众——生成多签 P2SH 地址前,先确保公钥为压缩形式,再按二进制字典序排序后组装赎回脚本;收到非压缩公钥要按不兼容处理,而不是悄悄转换。
多签参与方:组建共同账户时只需共享所需签名数与各自主公钥;地址是否一致,取决于各方钱包是否都遵循本规范。
全节点与矿工、共识层:完全不必动。网络既不检查、也无法检查公钥排序。
六、现在算不算数,以及一个常见误读
状态为 Complete(已完成):它是一份写完并有实现采用的钱包约定,不是一条等待激活的网络规则。遵循它的钱包,对同一(公钥集合,门限)永远给出同一个 P2SH 地址;不遵循的也不会被网络处罚,只是与遵循者生成的地址不同。
常见误读:
“不按 BIP-67 排序做出的多签交易是无效交易。”
不对。排序发生在构造赎回脚本、生成地址的阶段,是链下约定;链上验证只看脚本与签名本身是否成立。排序不合规的后果是互通性——伙伴钱包认不出你的地址——而不是共识层面的无效。
七、延伸
- 阅读版:https://bips.dev/67
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki
- 相关:BIP-11 M-of-N 标准交易、BIP-16 P2SH、BIP-45 确定性 P2SH 多签钱包
- 仓库总目录:https://github.com/bitcoin/bips
