协议演进 / BIP/比特币改进提案 / BIP-77
BIP-77
Payjoin 第二版:双方不必同时在线、收款方也不必自备公开服务器,改经一个不被信任的目录服务器用 Oblivious HTTP 异步转交加密的 PSBT。本 BIP 目前处于草案状态。
一、档案卡
| 编号 | BIP-77 |
|---|---|
| 标题 | Async Payjoin |
| 作者 | Dan Gould <[email protected]>、Yuval Kogman <[email protected]> |
| 指定日期 | 2023-08-08 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Draft(草案) |
| 前置依赖 | BIP-21、BIP-78、BIP-173、BIP-174 |
| 阅读版 | https://bips.dev/77 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0077.md |
二、放在哪一族
Payjoin 族的第二版,直接站在 BIP-78(A Simple Payjoin Proposal,原文称 Version 1)肩上,档案的前置依赖列明 BIP-21(URI)、BIP-78、BIP-173(Bech32)与 BIP-174(PSBT)。再往前追,同族的源头是已被 BIP-78 取代的 BIP-79(Bustapay)。
分工很清楚:BIP-78 定“双方如何合建一笔交易”——原始 PSBT、提案 PSBT、双方的核验清单、防探测与防偷钱的纪律,本 BIP 几乎全盘沿用(原文在收款方清单、付款方清单两处直接写“与 BIP78 相同”)。BIP-77 只换“双方如何把话传到”:从收款方自备端点的同步 POST,换成经目录服务器中转的异步加密留言。它还借用了 BIP-324 v2 P2P 加密传输中的 ElligatorSwift 编码与 ChaCha20Poly1305 等现成件。
三、它要解决什么
3.1 第一版的两道采用门槛
原文点名 BIP-78 的要求已成为采用障碍:其一,收款方必须托管一个安全的、面向公网的 HTTP 服务器——移动端与网页环境很难满足;其二,通信是同步的,付款方与收款方必须同时在线。钱包开发者把这两条视为 Payjoin 落地的拦路虎。
3.2 隐私的起点不能丢
动机部分先回到中本聪在白皮书里点过的风险:多输入交易必然暴露这些输入同属一人。Payjoin 正是冲着共同输入所有权启发式去的。同时原文指出,Payjoin 的输入批处理比交易所普遍用的输出批处理更省区块权重;两者结合,同等资金流动可用更少权重、更低费用完成。应用上,收款时顺手合并 UTXO 是自然场景;更进一步还能做交易切穿(cut-through):收款方在同一笔交易里再把钱转给第三方,例如交易所用一笔交易同时处理充值与提现,不必再花第二笔。
本 BIP 的目标因此收得很窄:不削弱第一版的收款功能(含付款输出替换),只把协调机制换成适合大规模实现的异步做法——用成熟的 Web 标准与已验证的比特币原语来拼。
四、规则本身
4.1 总览:目录、邮箱与轮询
双方不再直连,而是各自与一个不被信任的第三方目录服务器(directory)打交道,用存储转发的方式异步交换端到端加密的消息:
- 收款方先与目录完成 OHTTP 引导(见 4.2),再分享一个 Payjoin URI,其中
pj参数指向目录上一个一次性的邮箱(mailbox)端点; - 付款方把原始 PSBT(即一笔已完全签名的兜底交易)加密后 POST 到收款方邮箱,并生成自己的回复邮箱;
- 收款方轮询自己的邮箱取到原始 PSBT,加工成提案 PSBT,加密后 POST 到付款方的回复邮箱;
- 付款方轮询取回提案,按 BIP-78 的清单核验、签名、广播。
消息缓存在目录里,双方都能容忍临时掉线、回来轮询续上。任一方在任何时点都可以改广播原始 PSBT 描述的兜底交易;原始与提案花的是同一批输入,互斥,只有一笔能上链。
4.2 会话怎么建:URI、邮箱与片段参数
收款方须先发现目录的 OHTTP 密钥配置(Key Configuration),引导方式可变(从 URI、受信应用二进制中取得,或经 CONNECT、WebSocket、Tor、VPN 等取回),但必须满足 OHTTP 的一致性要求、且不应把收款方 IP 暴露给目录;目录的 OHTTP 网关必须支持按 RFC 9540 在 /.well-known/ohttp-gateway 取密钥配置。
Payjoin URI 沿 BIP-21(原文亦提 BIP-321)的 bitcoin URI,pj 参数的值就是邮箱端点 URL;也可用 req-pj 表示 Payjoin 必选。不懂 Payjoin 的付款方会忽略 pj、按普通地址付款。
会话专属参数不新开 URI 参数,而是编码在邮箱 URL 的片段(fragment)里(片段分隔符 # 在 URI 中须百分号编码为 %23):用类 Bech32 的大写编码、无校验和、以 - 分隔(为兼容旧稿,2026 年前也应接受 + 分隔且不强制顺序),字典序排列。已定义三个:EX 会话过期时间(Unix 时间)、OH 目录 OHTTP 密钥配置的紧凑形式(2 字节密钥标识 + 33 字节压缩公钥)、RK 收款方密钥(33 字节压缩公钥,付款方用它发起与收款方的 HPKE)。
邮箱由 Short ID 标识:取 33 字节压缩公钥的 SHA-256、截断 8 字节(64 位)、用 Bech32 字符集大写编码,作为邮箱 URL 的路径。原文专门算过 64 位的碰撞概率:即便按全网交易量上界估算,单个会话撞上的概率也远小于 1e-10。
整个邮箱 URL(含片段)要求大写编码,理由是便于解析、且能让二维码编码器使用更紧凑的字母数字模式;pj 参数应放在 URI 最后,避免二维码模式来回切换。
4.3 消息怎么封:HPKE + OHTTP 双层加密
端到端一层用 HPKE:曲线选 secp256k1 的 DHKEM(HKDF-SHA256),对称算法选 ChaCha20Poly1305——原文给的理由是这些原语在 Bitcoin Core 里已有(ChaCha20Poly1305 即 BIP-324 所用),不必为 TLS 另引依赖,因为 Core 里没有 TLS。
线格式上,HPKE 的公钥用 ElligatorSwift 编码成 64 字节,让目录看到的密文与随机数不可区分。付款方的消息(域分隔字符串 PjV2MsgA)总长定死 7168 字节:64 字节 ElligatorSwift + 密文(内含 33 字节回复密钥、填充后的明文与 16 字节 AEAD 标签);收款方的提案消息(PjV2MsgB,用 HPKE Auth 模式、以收款方密钥认证)同样 7168 字节。明文是 base64 的 PSBT 加一行可选参数——BIP-78 的可选参数在这里必须放进密文正文、不能再放 URL 查询串;v= 版本参数因 HPKE 已做域分隔而冗余,应省略。会话密钥都是一次性的:收款方密钥与付款方回复密钥每场会话只用一次。
客户端与目录之间再套一层 OHTTP(RFC 9458):内层请求先按 BHTTP(RFC 9292)序列化、用随机数据填充(不用 BHTTP 惯常的零填充,理由是为将来的多跳混网留不可区分性),整体封装为定长 8192 字节;响应则用请求 HPKE 上下文导出的秘密加密。OHTTP 的作用是让目录和中继都关联不到客户端 IP:目录只见中继、双方只见目录。空邮箱的 GET 应阻塞等待消息或 30 秒超时,这个时长取的是多数 HTTP 客户端的默认超时。
还有一个目录与中继的解耦设计:RFC 9458 本要求每个中继只对接一个网关,容易让某家目录垄断。目录可在 /.well-known/ohttp-gateway 对带 allowed_purposes 的查询回一个魔术字符串(BIP77 454403bb-…),向任意中继表明自己愿意承接本用途,中继就不必与目录一对一绑定。
4.4 PSBT 纪律:与第一版同规
原始 PSBT 必须:UTXO 数据完整、已完全签名、不带全局 xpub 与密钥路径等不必要字段、可广播;可以捎带批处理用的无关输出。提案 PSBT 必须:UTXO 完整、含原始的全部输入、含不属于收款方的全部输出、新增项插在随机位置;不得打乱既有顺序、不得降低绝对手续费;可以新增输入输出、可以移除或修改收款方自己的输出。两份清单的细目原文直接援引 BIP-78,不在此另立一套。
会话过期(EX)是异步版必须显式化的东西:BIP-78 是同步协议、没有标准过期机制,却又建议在对方离线时广播原始 PSBT,广播时机含糊、且自动化收款方还怕探测攻击。本 BIP 因此要求把过期时间写进 URI 让付款方知情;同时原文坦言,付款方无法阻止收款方在过期前就广播兜底交易。
4.5 向后兼容的明文通道
目录也可以收不经 OHTTP 的 HTTP/1.1 POST,兼容 BIP-78 的付款方。兼容路径下,因 BIP-78 的载荷既不加密也不认证,目录被视为 BIP-78 语境里的“不安全的 Payjoin 服务器”,收款方必须设 pjos=0 禁止输出替换,防止恶意目录改道收款输出。
收款方如何分辨版本:经封装回来的正文若是 UTF-8 明文,即按 BIP-78 处理。回 BIP-78 付款方时,提案不得 HPKE 加密,须以 base64 明文作为 PUT 请求的正文,发到收款方自己的邮箱(第一版付款方没有回复密钥、无从派生回复邮箱),且须在 30 秒内回,否则目录应按 BIP-78 回 unavailable 错误。
4.6 新增的攻击面
目录 DoS:邮箱存的是任意加密载荷,目录易被灌满。缓解办法是要求授权令牌,但令牌必须不可关联以保隐私;具体机制不在本 BIP 范围内。网络隐私:必须用 OHTTP 才能把双方 IP 对目录隐藏;付款方若绕过中继直连目录,IP 可能经目录被收款方得知——因为目录正是收款方指定的。
定长填充还有一层用意:封装消息恒为 8192 字节、端到端消息恒为 7168 字节且外观近随机,目录与中继无法区分消息种类;8KB 也小到不适合拿目录传图等滥用。
五、谁必须动
普通持币人:无感。不支持 Payjoin 的钱包忽略 pj 参数按普通付款走;支持第一版的钱包也能走兼容通道,只是享受不到异步与加密。
钱包开发者:在 BIP-78 的 Payjoin 逻辑之上,再实现目录协议:OHTTP 引导与封装、HPKE(secp256k1 DHKEM + ChaCha20Poly1305)的端到端加解密、邮箱轮询、片段参数的编解码、定长填充与会话过期处理。原文给的参考实现是 rust-payjoin 一套(含客户端、目录与开发包)及 payjoin-cli。
收款方与商户系统:不必再自备面向公网的安全端点,也不必与付款方同时在线——这是本 BIP 主要卸下的负担。代价是要接入一个目录、生成带 EX/OH/RK 的 URI 并轮询邮箱。
目录运营方:新角色。要托管邮箱端点与 OHTTP 网关、按定长格式存转消息、处理空邮箱的长轮询,并自担防洪泛与令牌策略。
全节点与矿工:不涉及。最终上链的仍是 BIP-78 意义上的普通协同交易。
六、现在算不算数,以及一个常见误读
状态为 Draft(草案),文档自身版本 0.2.0(变更记录:0.1.0 于 2025-05-28 并入为首个草案版,0.2.0 于 2025-07-08 把片段参数分隔符由 + 改为 - 并要求字典序)。草案意味着规范仍可能变动,实现者应按草案对待,不能把细节当已冻结的标准。它也没有取代 BIP-78:原文自称是相对第一版的第二版、且向后兼容,第一版目前仍是 Deployed。
常见误读:
“有了 BIP-77,目录服务器就成了要信任的第三方,Payjoin 的隐私反而倒退了。”
不对。原文对目录的定位从第一句就是 “untrusted”(不被信任):消息在到达目录前已端到端 HPKE 加密,目录只能存转密文;OHTTP 又把客户端 IP 与目录隔开,定长填充让目录连消息种类都分不清。目录能做的恶主要是拒绝服务(不转、灌满),原文也把这点明写为攻击面并要求令牌不可关联——它换走的是“收款方必须自备服务器”这一可用性负担,而不是引入一个能看钱、能改钱的中间人。
七、延伸
- 阅读版:https://bips.dev/77
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0077.md
- 相关:BIP-78 简单 Payjoin 提案(第一版)、BIP-79 Bustapay、BIP-174 PSBT、BIP-324 v2 P2P 加密传输
- 仓库总目录:https://github.com/bitcoin/bips
