协议演进 / BIP/比特币改进提案 / BIP-351
BIP-351
让付款双方仅凭一个可公开分享的支付码,用纯链上方式算出只有彼此能算出的收款地址,每笔付款地址都不同。本 BIP 目前处于已关闭状态。
一、档案卡
| 编号 | BIP-351 |
|---|---|
| 标题 | Private Payments |
| 作者 | Alfred Hodler <[email protected]>, Clark Moody <[email protected]> |
| 指定日期 | 2022-07-10 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Closed(已关闭) |
| 阅读版 | https://bips.dev/351 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0351.mediawiki |
二、放在哪一族
可复用收款标识与隐私支付族。它要接的是 BIP-47(Reusable Payment Codes,可复用支付码)留下的坑:支付码可以公开、可以反复收款,但通知方式会暴露谁在给谁付款。
同族的先后关系大致是:
BIP-32:分层确定性钱包,支付码与双方密钥都从种子派生
BIP-44:多账户层级结构,BIP-351 的派生路径沿用它的层级
BIP-47:可复用支付码,先行者,也是本 BIP 主要想改进的对象
BIP-352:静默支付(Silent Payments),后来同方向的另一条路线——不需要链上通知交易
与 BIP-352 相比,BIP-351 仍然需要一笔通知交易,只是把通知做得让外人认不出来;BIP-352 则连通知都省了。两条路线解决的是同一个问题:收款标识公开分享时,如何不牺牲隐私。
三、它要解决什么
收款方想长期用一个标识收款,又不想丢隐私,原有办法各有硬伤,原文逐一列过:
- 静态地址:只适合私下分享的一次性付款。反复用同一个地址收款就是地址复用,隐私尽失;拿来收捐赠更糟,地址会成为链上数据收集与分析的焦点。
- 分享 BIP32 扩展公钥(xpub):只适合两方之间反复付款。同一个 xpub 不能再给第三个人,否则整条收款链都会泄漏;xpub 本身也不说明地址类型,付款方可能打出收款方花不了的脚本。
- 分享带 xpub 的 BIP380 描述符:解决了地址类型问题,但描述符支持还不普及,移动钱包尤其如此。
- 自建支付服务器:每次付款现生成新地址,通常只有商家有条件维护;中心化服务器还有被远程或物理关停的风险。
- BIP-47 支付码:补上了多数短板,但通知机制依赖人人共用的、公开已知的通知地址。付款方若选币不慎——通知用的 UTXO 与自己身份有关联——就会在链上永久暴露“我正在给这个人付款”;而且 BIP-47 同样不说明地址类型,收款钱包得监视由一个公钥能生成的全部地址类型。
BIP-351 的目标是:支付码可以公开贴出来,每个付款方都为它算出一组独一无二的地址;通知只走链上,但不指向公开已知的地址,把链上足迹压到最小。
四、规则本身
4.1 支付码的结构
收款方按 BIP44 层级派生密钥,路径为 m / purpose' / coin_type' / account',其中 purpose 定为 351。路径处的公钥 P(私钥 p)就是支付码的核心。
支付码共 35 字节:前 2 字节是地址类型标志,后 33 字节是压缩公钥 P。用 bech32m 编码,主网人类可读前缀是 pay,测试网是 payt。
地址类型用 16 位大端位标志表示,当前已定义的只有三位:P2PKH(0x0001)、P2WPKH(0x0002)、P2TR(0x0004)。其余位保留给未来的地址类型。所有密钥都必须是压缩格式,用非压缩密钥在任何环节都不合法。
4.2 通知:40 字节的 OP_RETURN
付款方 Alice 想开始给收款方 Bob 付款时,先发一笔通知交易,其中带一个 40 字节的 OP_RETURN 输出,内容按顺序拼接:
- 搜索键
PP(固定 ASCII,2 字节); - 通知码(4 字节):对 ECDH 共享点
n_x * P做 SHA256,取前 4 字节; N_x(33 字节):Alice 为这个收款方专门派生的子公钥,索引 x 对每个收款方唯一;- 地址类型序号(1 字节):Alice 从 Bob 接受的地址类型中选定一种,此后只能按这一种类型付款。
Bob 扫描区块里的 OP_RETURN,凡以 PP 开头的,就用自己的私钥算 H(N_x * p) 比对前 4 字节:对上,就是发给自己的通知,把 N_x 和地址类型存下来,开始监视双方共同算出的那组地址。对不上就丢弃。
这个设计的关键点有三个:一是通知不发给任何公开地址,外人看不出通知是给谁的;二是 Alice 换一个索引 x 就能以全新身份重新通知,不与旧身份关联,也可以借此改换地址类型;三是通知码只截 4 字节,误报概率约 43 亿分之一,代价只是多监视几个地址,却省下 28 字节。原文也提醒:Alice 若做好选币隔离,通知交易与后续付款都无法归因于双方;即便她用了与自己关联的币,链分析最多认出发送方,Bob 的隐私仍然完整。
链下通知(带外通知)不被禁止,但那样 Bob 就无法仅凭链上 OP_RETURN 恢复钱包,通知记录得自己另行备份。
4.3 收款地址怎么算出来
通知之后,双方共享一个秘密点:Alice 算 S = n_x * P,Bob 算 S = N_x * p,由 ECDH 性质两边结果相同。
Alice 维护一个针对 Bob 的计数器 c(64 位整数,每笔付款递增,以大端 8 字节喂入哈希),逐笔计算:
- 共享秘密
s = H(S | c); - 本笔收款公钥
P_c = P + s*G,再按通知时选定的地址类型把P_c编成地址付款。
Bob 在自己一侧镜像同样的计算生成监视列表;花费时私钥为 p_c = p + s。
4.4 扫描要求与兼容性
收款方必须能拿到完整区块,才能搜其中的 OP_RETURN 通知。原文特别指出:BIP-158 紧凑区块过滤器不覆盖 OP_RETURN 数据负载,轻客户端想用本标准,得靠外部服务发布带证明的通知交易(附录 B 的设想),或靠第三方把通知负载搭进无关交易(附录 C)。
向后兼容方面:本标准与 BIP-47 等以往静态支付码标准不兼容。它不设版本号,靠地址类型标志中的保留位扩展:旧支付码能被支持新类型的软件读取,新支付码里旧软件不认识的标志位会被忽略。
五、谁必须动
普通持币人:想隐私收款的一方生成支付码公开分享即可;付款方把对方支付码导入兼容钱包,钱包自动完成通知与地址计算。不需要运行特殊节点,但收款方钱包的扫描负担明显比普通钱包重。
钱包开发者:要实现支付码编解码(bech32m、pay 前缀)、purpose = 351 的派生、通知交易的构造与扫描、ECDH 地址推导与计数器管理,还要监视完整区块中的 OP_RETURN。原文给出了参考实现(rust-private-payments)与完整测试向量。
全节点与矿工:无特殊要求。通知交易与付款交易都是普通交易,本 BIP 不改任何节点规则。
共识层:不涉及。本 BIP 是应用层的钱包间约定。
六、现在算不算数,以及一个常见误读
状态为 Closed(已关闭)。原文变更记录写明:因缺乏活动(lack of activity)而移至 Closed。也就是说,这套方案写完了、也有参考实现,但没有形成持续推进的采用势头,流程上已经收束。它与同方向的 BIP-352 静默支付是并行探索的关系,不是被正式取代——档案里没有 Superseded-By 记录。
常见误读:“支付码公开贴出来,就等于把收款地址公开了,谁都能把付款都关联起来。”不对。支付码里只有收款方的公钥与可接受的地址类型;每笔收款地址还要经过付款方私钥参与的 ECDH 与计数器哈希才算得出,只有交易双方能算出同一组地址。外人拿着支付码,既算不出地址,也无法把不同付款方的付款关联到一起——这正是它与静态地址的根本区别。
七、延伸
- 阅读版:https://bips.dev/351
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0351.mediawiki
- 相关:BIP-47 可复用支付码、BIP-352 静默支付、BIP-32 分层确定性钱包
- 仓库总目录:https://github.com/bitcoin/bips
