协议演进 / BIP/比特币改进提案 / BIP-352
BIP-352
收款方只公开一个静态的静默支付地址,付款方为每笔付款算出独一无二的 Taproot 输出,无需交互、无需链上通知,链上也看不出关联。本 BIP 目前处于已完成状态。
一、档案卡
| 编号 | BIP-352 |
|---|---|
| 标题 | Silent Payments |
| 作者 | josibake <[email protected]>, Ruben Somsen <[email protected]>, Sebastian Falbesoner <[email protected]> |
| 指定日期 | 2023-03-09 |
| 讨论日期 | 2022-03-13 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Complete(已完成) |
| 依赖 | BIP-340, BIP-341, BIP-350 |
| 阅读版 | https://bips.dev/352 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki |
二、放在哪一族
隐私收款与可复用地址族。它与 BIP-351(Private Payments)解决同一个问题——收款标识公开分享时如何不丢隐私——但路线更彻底:连通知交易都不要。
它站在 Taproot 的肩膀上:
BIP-340:Schnorr 签名,密钥运算的基础
BIP-341:Taproot,所有静默支付收款输出最终都编码为 BIP-341 的 Taproot 输出
BIP-350:Bech32m 编码,静默支付地址用它编码
BIP-47 与 BIP-351:早期的支付码路线,都需要链上通知;BIP-352 把通知环节整个去掉
后续配套还有用 PSBT 发送与花费静默支付输出的提案(见本站 BIP 索引中 BIP-375、BIP-376),以及静默支付输出脚本描述符等钱包侧标准。
三、它要解决什么
保持隐私的基本要求是每笔交易用新地址。这通常需要收款方先交互交付一个新地址、一批地址,或者像 xpub 那样交付一个能按需生成地址的方法。但交互常常做不到、也不想要:捐赠页、公开收款页、离线场景,都需要一个能长期贴出来的静态标识。
以往用静态标识的协议靠区块链发通知来补交互,代价是:一次性付款成本变高、链上留下显眼足迹、通知元数据可能暴露发送方与接收方,而且收款方能把同一发送方的多笔付款全部关联起来,伤发送方隐私。
BIP-352 的目标清单在原文里列得很明确:不增加交易体积与成本;交易看起来与普通比特币交易无异、无法被分辨;外部观察者无法把交易关联到静默支付地址;无需发送方与接收方交互;同一发送方的多笔付款互不关联;每笔付款去往唯一地址、不会意外复用;支持付款标签;能用现有助记词或描述符方式备份恢复;扫描与花费职责可分离;兼容 CoinJoin 等协作交易;支持轻客户端;协议可升级。
代价也写明了:收款钱包必须扫描区块链才能发现付款。全节点做这件事可行,轻客户端则吃力——原文附录 A 把轻客户端支持列为开放研究问题,给出了若干设想,但不属于本规范正文。
四、规则本身
4.1 地址:一对公钥,Bech32m 编码
静默支付地址(version 0)装的不是一个公钥,而是两个:扫描公钥 B_scan 与花费公钥 B_spend,各 33 字节压缩格式,拼接成 66 字节后用 Bech32m 编码。主网人类可读前缀为 sp,测试网为 tsp,版本字符为 q(即地址以 sp1q 开头)。原文特意说明:这类地址至少 116 个字符,建议实现把长度上限放宽到 1023 字符,为未来版本留余地。
分两把钥匙的原因是安全分工:扫描需要私钥在线,b_scan 可以放在联网设备上找钱;b_spend 可以留在离线冷存储里,只在花钱时用。扫描方只有 B_spend 的公钥,算得出收款输出、却花不了。
用 BIP32 派生时,purpose 定为 352,且扫描与花费密钥都必须用硬化派生:扫描密钥路径 m / 352' / coin_type' / account' / 1' / 0,花费密钥路径 m / 352' / coin_type' / account' / 0' / 0。硬化派生保证导出扫描私钥不会牵连主密钥与花费私钥。
4.2 付款方怎么算出收款输出
简化情形:Alice 用自己的输入私钥 a、Bob 的扫描公钥做 ECDH,P = B_spend + hash(a·B_scan)·G,把 P 编码为一个 Taproot 输出付款。Bob 用 b_scan 与 Alice 输入的公钥 A 算出同一个值(因 a·B_scan == b_scan·A),扫描时对上即知是自己的钱;花费私钥是 b_spend 加上那段哈希微调。
规范在此之上加了三层处理:
- 多输出:同一笔交易给同一收款方多个输出时,引入计数 k(从 0 起),
P_k = B_spend + hash(共享秘密 || k)·G。Bob 找到P_0后依次试P_1、P_2……直到试不到为止。生成过的输出必须全部进入最终交易,漏掉中间任何一个,后面的就找不回来。 - 防地址复用:若 Alice 换一笔 UTXO、但用同一个公钥 A 再付一次,会算出相同目的地。为此引入
input_hash = hash(字典序最小的 outpoint || A),微调改为hash(input_hash·a·B_scan || k),保证每次付款唯一。取最小 outpoint 是为了让结果与输入最终排序无关,也照顾内存受限的硬件签名设备。 - 用全部输入:一笔交易有多个输入时,不用某一个输入的钥匙,而用全部合资格输入私钥之和(公钥之和)。这样 Bob 每笔交易只需一次椭圆曲线乘法、扫描成本大降,轻客户端配合 BIP-158 过滤器才成为可能;在 CoinJoin 里,Bob 也无从知道哪个输入属于 Alice。
合资格参与共享秘密推导的输入类型只有四种:P2TR、P2WPKH、P2SH-P2WPKH、P2PKH,且只许 X-only 与压缩公钥。带条件分支或多公钥的输入(如 CHECKMULTISIG)被排除,因为在协作交易中会引入可塑性。签名哈希类型不得使用 SIGHASH_ANYONECANPAY,否则签名后输入被改动,收款方就再也算不出共享秘密。
有个防滥用上限:共享同一扫描公钥的一组收款地址最多 K_max = 2323 个,超限即失败,以免恶意构造的交易让扫描方的计算量爆炸。
4.3 标签(Labels)
Bob 想区分同一地址收到的不同来源付款,不必公开多个地址(那会成倍增加扫描量),可以用整数 m 给花费公钥贴标签:B_m = B_spend + hash(BIP0352/Label, b_scan || m)·G,m 从 1 起。公布出去的各标签地址共享同一个 B_scan,所以原文提醒:外人能看出这些标签地址属于同一主体,标签是用来分辨“钱从哪来”,不是用来分隔身份。
m = 0 被保留作找零标签:钱包给自己找零时打上它,恢复钱包时就能认出哪些输出是自己的找零。每个收款钱包恢复时都至少应扫描找零标签,以保证跨钱包兼容。标签信息应写入备份;若不确定是否用过标签,恢复时建议预计算大量标签(原文举例 10 万个)再扫描。
4.4 收款方扫描与花费
一笔交易同时满足三个条件才需要扫描:至少含一个 BIP-341 Taproot 输出;至少有一个合资格类型的输入;不花费 SegWit 版本大于 1 的输出(为未来版本留干净的升级路径)。
扫描时 Bob 汇总全部合资格输入公钥、算 input_hash 与共享秘密,从 k = 0 起逐个生成候选输出与交易中的 Taproot 输出比对,并顺带检查标签(含找零标签)。原文特别警告:是否继续扫描(k 递增)必须以密码学上是否命中为准,不能以钱包策略为准——哪怕命中的输出因是粉尘而被钱包过滤掉,也必须继续试下一个 k,否则会漏掉同一发送方的后续输出。
花费时私钥为 (b_spend + t_k + 标签微调) mod n,按普通 BIP-341 输出花费即可。链上看,它就是一笔普通的 Taproot 花费。
4.5 向后兼容
静默支付引入了新地址格式与新的发送协议,与未实现本协议的旧钱包不兼容:旧钱包既不能向静默支付地址付款,也不能识别收到的静默支付输出。未来版本通过地址中的版本位升级,并要求尽可能让旧钱包能向新版本地址付款;破坏兼容的改动应另立新 BIP。
五、谁必须动
普通持币人:收款只多一件事——保管好种子,恢复钱包时要从钱包“生日”起重新扫描链上数据才能找回全部静默支付收款。付款给静默支付地址则与付普通地址无异,前提是钱包已实现本协议。
钱包开发者(发送方):选币时至少要有一个合资格输入、排除 SegWit 版本大于 1 的输入、Taproot 输入须能拿到密钥路径私钥(内部钥匙为 NUMS 点 H 的除外);按输入之和计算共享秘密;RBF 改动输入后必须重新推导静默支付输出。
钱包开发者(接收方):负担最重——实现全链扫描或接入能提供微调数据的服务、标签管理、找零标签扫描与备份恢复流程。原文附有 JSON 测试向量与 Python 参考实现,发送与接收两侧可分别对照测试。
全节点与矿工:无任何改动。静默支付交易就是普通交易,共识与转发规则都不变。
共识层:不涉及。本 BIP 是应用层协议。
六、现在算不算数,以及一个常见误读
状态为 Complete(已完成):指规范文本已经定稿完整,可以照着实现,而不是说全网或全部钱包都已采用。它不需要激活、不需要软分叉,算不算数取决于各个钱包是否实现发送与接收支持;实现进度参差,原文没有给出采用统计,本页也不臆测。
常见误读:“静默支付地址是一个可以反复用的链上地址,用了它就等于地址复用。”不对。sp1q... 地址本身从不上链,它只是扫描与花费两把公钥的编码;每笔付款真正落到链上的,是付款方用 ECDH 为这一笔单独算出的 Taproot 输出,每笔都不同,外部观察者无法把它们关联回那个公开地址。被“复用”的只有链下分享的标识,不是链上地址。
七、延伸
- 阅读版:https://bips.dev/352
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki
- 相关:BIP-341 Taproot、BIP-351 隐私支付、BIP-47 可复用支付码
- 仓库总目录:https://github.com/bitcoin/bips
