协议演进 / BIP/比特币改进提案 / BIP-75

BIP-75 用支付协议加密的带外地址交换

给支付协议加一来一回的带外地址交换:付款方先发可自愿签名的 InvoiceRequest,收款方再把 PaymentRequest 加密回传,让地址不必复用、身份不必裸奔。本 BIP 目前处于已部署状态。

一、档案卡

档案卡
编号BIP-75
标题Out of Band Address Exchange using Payment Protocol Encryption
作者Justin Newton <[email protected]>、Matt David <[email protected]>、Aaron Voisine <[email protected]>、James MacWhyte <[email protected]>
指定日期2015-11-20
层级Applications(应用)
类型Specification(规范类)
状态Deployed(已部署)
阅读版https://bips.dev/75
官方原文https://github.com/bitcoin/bips/blob/master/bip-0075.mediawiki

二、放在哪一族

支付协议族的扩展件,直接长在 BIP-70(Payment Protocol)之上,与 BIP-71、BIP-72、BIP-73、BIP-74 同族。

BIP-70 的基本流向是单向的:收款方(商户)生成 PaymentRequest,付款方下载、付款、回 Payment 与 PaymentACK;能出示 PKI 身份材料的也只有收款方。BIP-75 把流向补成双向:付款方先开口、也可亮明身份,收款方回传的 PaymentRequest 在交给 TLS 之前先再加一层加密。同族里它是最重的一份——新消息、新封装、新加密流程一应俱全,原文篇幅也远长于 71–74。

三、它要解决什么

3.1 地址靠静态复用或 X-Pub,都有代价

想让熟人反复付款而不必每次问地址,常见办法都不理想:静态地址损害隐私且地址复用被视为安全风险;给出 BIP32 的 X-Pub 可以逐笔生成新地址,但为每个联系人都盯一条 X-Pub 链,对移动钱包太重,而且对方一旦丢失对应私钥,钱仍可能打进一个“死”地址。

原文给的替代图景是“地址簿只存公钥”:通过钱包名、二维码、短信或邮件里的 URI 等方式把联系人加进来;真要付款时,付款方钱包在后台与收款方钱包通信,现取一个新地址。对方钱包已丢失或销毁、联系不上,就不会把钱打出去。

3.2 收款方在 BIP70 里是被动公开的

BIP-70 下,任何人来请求,收款方就把收款地址与身份信息交出去。原文希望反过来:收款方先看到付款方的身份信息,再决定要不要分享自己的支付信息——可以只给白名单付款方自动发新地址,也可以挡住不请自来的请求。

3.3 移动与离线钱包需要存储转发

移动钱包不常在线,地址交换需要一个可暂存消息的 Store & Forward(存储转发)服务器代为中转。但若消息明文过中转,服务器被攻破就能读、能改地址与支付细节。原文的动机因此落到三点:支付细节只能被交易双方看见;支持存储转发以便移动钱包也能签发与 serve PaymentRequest;付款方可自愿向收款方分享身份,便于生成含付款方信息、人类可读的链下交易记录与可核验的财务凭证。

四、规则本身

4.1 扩展 pki_type

BIP-70 的 PaymentRequest 里有 pki_type 字段。本 BIP 把可选值扩为三项:x509+sha256(X.509 证书,沿 BIP70)、pgp+sha256(OpenPGP 证书)、ecdsa+sha256(secp256k1 的 ECDSA 公钥)。双方都可提供 PKI 数据,不再只有收款方。注意:SHA1 在 BIP70 里曾受支持,本 BIP 已弃用,只支持 SHA256;值里仍写哈希名是为前后兼容。

4.2 新消息:InvoiceRequest

新增 InvoiceRequest 消息,由付款方(Sender)发给收款方(Receiver),请对方据此生成并回传 PaymentRequest。字段包括:付款方 SEC 编码的 EC 公钥 sender_public_key、可选金额 amount(以聪计,默认 0)、pki_type 与 pki_data、给收款方看的备忘 memo、回传地址 notification_url,以及依 PKI 类型计算的 signature。不附证书时 pki_type 设为 none。

4.3 两种封装:ProtocolMessage 与 EncryptedProtocolMessage

所有支付协议消息都必须装进封装消息里传送。ProtocolMessage 是明文封装,带版本号(本协议为 1)、状态码、消息类型、序列化消息本体、状态说明与整场交换的唯一 identifier;EncryptedProtocolMessage 则在此之上加密,带双方公钥、随机数 nonce、签名等字段。一旦一场交换开始用加密封装,后续通信必须全程加密;一般也都应加密,唯一的例外是收款方公钥尚未知时,第一份 InvoiceRequest 可以用明文封装发。

消息类型用可扩展的 ProtocolMessageType 枚举区分:InvoiceRequest、PaymentRequest、Payment、PaymentACK 等。版本号协商也有明文规则:收到高于自己理解版本的报文,要回一个状态码 101(version too high)、并标明自己能懂的最高版本,对方据此降版重发或中止。

4.4 加密怎么做

加密封装用 ECDH 算出共享秘密点:以其 X 坐标的 SHA512 摘要喂给 HMAC_DRBG(以消息的 nonce 为 DRBG 的 nonce),再由 DRBG 产出 AES-256-GCM 的 256 位密钥与 96 位 IV,对序列化消息做 AES-256-GCM 认证加密。原文选用 GCM 正是因为它自带认证,不必再单独做消息哈希。GCM 的 16 字节认证标签必须前缀在密文之前;status_code 与 status_message 不加密、但要作为附加认证数据纳入计算,防篡改。nonce 以微秒级纪元时间充当、绝不可重复。经 HTTP 传输时,两种封装各有专用 Content-Type;状态码表还细列了金额过高/过低/无效、证书必填/过期/无效/被吊销等情形。

标准交换的顺序是:付款方建 InvoiceRequest → 封装后发出 → 收款方取出并建 PaymentRequest → 用加密封装回传 → 付款方验证后,按 BIP-70 继续处理 Payment 与 PaymentACK(同样装进加密封装)。

4.5 存储转发下的注意点

原文还给存储转发服务器留了防滥用规则示例:同一 identifier 下后续消息必须沿用同一对收发公钥;每种消息原则上只存一份(Payment 可覆盖更新);消息存到对方确认收到或超时为止。并提醒客户端:收款方可能不回 ACK 就直接广播交易;若要更新一份 Payment,应至少引用原交易的一个输入,防止收款方把两笔都广播、收两次钱。

五、谁必须动

普通持币人:无强制动作。若钱包支持,体验上的变化是:可以只存联系人公钥、每次现取新地址;也可以在分享自己的收款信息前,先看对方是谁再决定。

钱包开发者:动作最重。要实现 InvoiceRequest、两种封装消息、版本协商与状态码处理、ECDH + HMAC_DRBG + AES-256-GCM 的加解密管线、公钥与签名的编码规则(X.509 用 DER、EC 公钥用 SEC 编码、ECC 签名用 SHA-256 + DER),以及最初如何取得对方公钥(钱包名解析、密钥服务器、二维码等方式原文列为可选路径)。

商户与服务方:若要做存储转发或自动应答,需按 identifier 与公钥绑定来存取消息、按状态码回错,并理解“可以不回 ACK 直接广播”这一既有行为。

全节点与矿工:不涉及。全部交换都在链下,不改共识、不改交易格式。

六、现在算不算数,以及一个常见误读

状态为 Deployed(已部署)。它是对 BIP-70 的正式扩展规范:双向、许可式、加密的地址交换。Deployed 只说明该规范在仓库中的状态,不等于原文给出了今天的实际采用清单——原文列有 Store & Forward 服务器与客户端的参考实现链接,也没有统计哪些钱包在用,本页不替它补采用情况。

常见误读:

“BIP-75 的加密是为了把交易本身藏起来。”

不对。它加密的是链下交换的支付协议消息——InvoiceRequest、回传的 PaymentRequest 等——目的是让中间人(含存储转发服务器)看不到地址与支付细节。最终交易仍按 BIP-70 构造并广播上链,链上可见性不因本 BIP 改变。另一层自愿签名解决的是“对方是谁”,不是“链上藏什么”。

七、延伸

本页内容整理自 bitcoin/bips 仓库与 bips.dev,事实已与仓库核对;解读仅供学习参考。