协议演进 / BIP/比特币改进提案 / BIP-322
BIP-322
提出基于比特币脚本的通用签名消息格式:不再局限于 P2PKH 地址,任意脚本控制的币都能签消息、证明收款资格或展示资金控制。本 BIP 目前处于已完成状态。
一、档案卡
| 编号 | BIP-322 |
|---|---|
| 标题 | Generic Signed Message Format |
| 作者 | Karl-Johan Alm <[email protected]>、Oliver Gugger <[email protected]> |
| 指定日期 | 2018-09-10 |
| 讨论日期 | 2018-03-14 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Complete(已完成) |
| 依赖文档 | Requires: BIP-174、BIP-340、BIP-341、BIP-342 |
| 阅读版 | https://bips.dev/322 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki |
二、放在哪一族
消息签名族。旧的标准做法是“用地址对应的私钥签一段消息”,以证明签者与收款地址的关系;这一做法的正式文档是 BIP-137(用私钥签署消息)。但它只支持 P2PKH 一类地址,SegWit、多签、Taproot 等现代脚本无从下手。
BIP-322 把签名对象从“某个私钥”推广到“某个脚本”:只要能满足脚本,就能签。它的依赖关系写在档案里:Requires BIP-174(PSBT)、BIP-340、BIP-341、BIP-342(Schnorr 签名与 Taproot 一族)。其 full 签名形式在结构上又与 Signet 的挑战—求解模式相通,原文称它与 BIP-325(Signet)所用的挑战类似。
三、它要解决什么
3.1 旧格式只认 P2PKH
原文动机开门见山:现行消息签名标准只适用于 P2PKH(以 1 开头)的收款地址。本 BIP 提议用一种基于比特币脚本的方法把标准扩展、普遍化,使任何脚本控制的币原则上都能被签——同时为便于与既有签名硬件互操作,还定义一种形似比特币交易的消息签名格式(其中含有一个无效输入,因此不可能在任何真实网络上被花费)。
3.2 旧签名并不真正证明知道私钥
原文指出的第二个缺陷在密码学层面:现行消息签名格式使用 ECDSA 签名,而这类签名并不承诺公钥,因而并不真正证明签者知道任何秘密密钥——有效的签名可以被第三方微调,变成对某些相关密钥同样有效的签名。
3.3 它能证明什么、不能证明什么
原文罕见地用整段篇幅划界,读时不应跳过:
- 本 BIP 只处理一种用例:签名者表明自己将能够控制发往某个收款地址的资金;
- 任何消息签名协议都不可能真正“证明控制资金”:签名一经产生即告过时,且持有密钥的人可能愿意替他人签消息、却不愿替他人签真实交易。这两个局限,任何消息签名协议都修复不了;
- 证明“某笔先前交易是签名者发出的”,用本 BIP 同样做不到。
四、规则本身
4.1 四种签名形态
本 BIP 规定三种签名格式,另加一个资金证明变体。签名者必须在签名前加上所用变体的前缀;为兼容定稿之前的实现,验签者在无前缀时可以假定其为 simple 变体。
- Legacy(旧格式):紧凑型、可恢复公钥的 ECDSA 签名,经 base64 编码,无前缀;兼容 P2PKH 等。原文要求新证明对所有收款地址格式都应使用新格式,legacy 格式可以保留,但必须限制在 legacy P2PKH 地址上使用。
- Simple(简单格式):前缀 smp。签名是见证栈(witness stack),按共识编码后 base64;兼容 P2WPKH、P2WSH、P2TR(原文注明不含时间锁脚本)。
- Full(完整格式):前缀 ful。签名是完整的 to_sign 交易(见 4.2 节),按共识编码后 base64;兼容全部脚本类型。
- Full (Proof of Funds)(资金证明变体):前缀 pof。签名是已定稿的 PSBT 包;同样兼容全部脚本类型,并额外证明对一组 UTXO 的控制。
4.2 两笔虚拟交易:to_spend 与 to_sign
Full 形式的核心是构造两笔虚拟交易:
- to_spend:nVersion 与 nLockTime 均为 0;其唯一输入指向全零哈希、序号 0xFFFFFFFF 的不存在输出,序列号为 0,scriptSig 为 OP_0 压入 32 字节的 message_hash;其唯一输出金额为 0,scriptPubKey 就是被证明的脚本 message_challenge。其中 message_hash 是对消息做的 BIP-340 带标签哈希,标签为 BIP0322-signed-message,消息按原文取用,不加长度前缀与结尾空字符。
- to_sign:唯一输入花费 to_spend 的输出;见证(或在 full 形式下按需设置的 scriptSig)里放 message_signature;唯一输出金额为 0、scriptPubKey 为 OP_RETURN。
如此设计的效果是:验证“签名”,就是验证一笔假交易能否满足真实脚本——脚本解释器怎么验真实花费,就怎么验消息签名。因此任意脚本(包括多签与 Taproot 脚本路径)天然被覆盖。原文要求:除 legacy 外,所有形态的这两笔交易都必须能通过全部共识检查,唯一例外是那个全零前序输出本就不存在。
4.3 资金证明变体的附加规则
资金证明在 full 形式上再进一步:签名者除对单个地址的脚本签消息外,还证明对一任意自选 UTXO 集合的控制。做法是把想展示的 UTXO 全部作为 to_sign 的附加输入,并按“真的在花费它们”那样填好见证与 scriptSig,同时为每个附加输入设置对应的(Non-)Witness UTXO 字段(同一交易的多个输出可作优化省略)。原文划界:这份清单不声称完整(不表示“该地址的全部 UTXO 就是这些”),也不声称未花费(验签者须自行查区块链);验资金者因此需要访问当前 UTXO 集,离线验签者只能证明附加输入见证栈的密码学有效性。
4.4 验证流程与结果
验签者拿到地址、签名与消息后,输出三种状态之一:带时间锁但其余有效时报“在时间 T 有效、年龄 S”;无法检查脚本时报“不确定”(inconclusive);任何检查失败则报“无效”(invalid)。流程概要是:由消息与地址算出 to_spend;把签名解码为 to_sign;若为完整交易或 PSBT,逐项确认各字段与规范一致(尤其第一输入须花费 to_spend 的输出、输出恰好一个且合乎规定);最后确认两笔交易合起来满足全部共识规则。
原文另设有基于 PSBT 的签名流程,分 creator、signer、finalizer 三种角色构造与签署,与 BIP-174 的 PSBT 工作流衔接。
五、谁必须动
普通持币人:当交易所、服务商或交易对手要求“签个消息证明地址是你的”时,由钱包代为生成 BIP-322 签名即可;需要理解的是原文的划界——这种签名证明的是“能控制发往该地址的资金”,不是资金所有权的法律凭证,更不证明某笔历史交易出自你手。
钱包开发者:这是主要行动方。需实现 simple 与 full 两种新格式(前缀、两笔虚拟交易的构造、带标签的消息哈希),处理各类脚本类型的见证栈;支持资金证明的,还要实现 PSBT 变体与附加输入的 UTXO 字段规则。验签一侧须实现三态输出,不得把“不确定”当成“有效”。
硬件签名设备:原文的设计目标之一就是与既有签名硬件易于互操作:签名对象被做成交易形态,硬件可以按近似真实交易的方式呈现与签署;实现时要留意 to_sign 中的无效前序输出,确保设备不会把它误当真实付款。
全节点与矿工:无需改动。签名与验签都发生在链下,借用的只是脚本解释规则本身。
共识层:本 BIP 不修改共识规则。
六、现在算不算数,以及一个常见误读
状态为 Complete(已完成):规范文本已经定稿完备,可供钱包实现与互操作。它完成的是“格式标准”,不是共识升级——某个钱包是否支持 BIP-322 签名,取决于该钱包的实现,本站不臆测各产品的采用情况;原文提供的参考实现与测试向量正是为互操作准备的。
常见误读:
“有了 BIP-322 签名,就能证明这笔钱是我的、这笔交易是我发的。”
原文明确否定这种读法:它能表明的只是签者将能够控制发往该收款地址的资金;它不能证明签者发出过某笔先前交易,也不可能在协议层面上“真正证明控制资金”——签名会过时,持钥人也可能替人代签。把 BIP-322 签名当成所有权铁证,是超出规范承诺的推论。
七、延伸
- 阅读版:https://bips.dev/322
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki
- 相关:BIP-137 用私钥签署消息、BIP-174 PSBT 格式、BIP-340 Schnorr 签名
- 仓库总目录:https://github.com/bitcoin/bips
