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

BIP-62 处理可锻性

提议新增七条共识规则,逐一封堵交易可锻性的主要来源,使发送方不主动规避时交易无法再被第三方改形。文档自述未完成,提案最终关闭,未部署。本 BIP 目前处于已关闭状态。

一、档案卡

档案卡
编号BIP-62
标题Dealing with malleability
作者Pieter Wuille <[email protected]>
指定日期2014-03-12
层级Consensus (soft fork)(共识(软分叉))
类型Specification(规范类)
状态Closed(已关闭)
阅读版https://bips.dev/62
官方原文https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki

二、放在哪一族

交易可锻性(malleability)治理族,也是共识规则收紧型(软分叉)提案的一份早期样本。它在引入机制上借用 BIP-34 的办法(用区块版本号达到阈值后激活新规则),原文的 Block validity 一节明确如此说明。

原文开头有一行醒目的声明:本文档仍在进行中(work in progress),未完成、未实现、也不适合部署。读这份文档,要带着这个前提——它是 2014 年时点上对可锻性来源的一次系统清点与逐项封堵尝试,而不是一份生效过的规范。

三、它要解决什么

截至 2014 年 2 月,比特币交易在多个方面是可锻的:一笔有效交易可以在传播途中被修改而不失效,修改者并不需要相关私钥。原文列出它带来的麻烦:

原文清点的可锻性来源共有九项:

  1. 非 DER 编码的 ECDSA 签名:参考客户端用 OpenSSL 验签,而 OpenSSL 接受比 DER 标准更宽松的序列化。自 v0.8.0 起,非 DER 签名已不再被中继;
  2. scriptSig 中的非压栈操作:任何能得到相同压栈结果、但不只是压入数据的脚本操作序列,都给出另一笔同样有效的交易;
  3. scriptSig 中非标准大小类型的压栈操作:压栈操作有多种(OP_0、单字节压栈、至多 75 字节的数据压栈、OP_PUSHDATA1/2/4),后者与前者结果相同,于是产生额外可能;
  4. 数字压栈的零填充:被当作数字解释的栈值可以被零填充出多种编码;
  5. ECDSA 签名本身的可锻性:把签名中的 S 取负(模曲线阶)仍然有效;
  6. scriptSig 中多余的操作:在脚本开头添加不被对应 scriptPubKey 消费的额外压栈;
  7. 被脚本忽略的输入:例如 scriptPubKey 以 OP_DROP 开头时,scriptSig 最后一个压栈总被忽略;
  8. 基于 sighash 标志的掩蔽:sighash 标志可以让签名忽略脚本的某些部分;
  9. 发送方重新签名:发送方(或任何持有相关私钥的人)总能为同一组输入输出造新签名。

原文的判断是:前六项与第七项的一部分可以用新增共识规则修复,后两项修不了。即使有了新规则,只要输出脚本不属于“安全集合”,其花费交易仍可能被锻造;但若限定使用安全的输出脚本集合,新规则可以让花费交易“可选地”不可锻——由花费者自己选择,他本人总能借第 8、9 项绕开。

四、规则本身

4.1 七条新规则

与可修复的来源逐项对应:

  1. 签名须规范 DER 编码:传给 OP_CHECKSIG、OP_CHECKSIGVERIFY、OP_CHECKMULTISIG、OP_CHECKMULTISIGVERIFY 的 ECDSA 签名必须严格 DER 编码;空字节数组(OP_0 的结果)也被允许,以便紧凑地构造一个故意无效的签名。用非 DER 签名验证会让整个脚本求值为假,而不只是该次验签失败;
  2. scriptSig 只许压栈:scriptSig 中只允许数据压栈,执行任何其他操作会让脚本求值为假;
  3. 压栈须用最小操作:必须尽可能使用最短的压栈操作;能用更短方式编码却用了更长操作的,脚本求值为假;
  4. 数字须最短编码:凡脚本操作码把栈值当作数字消费时,其编码必须是最短形式,且不允许“负零”;
  5. 签名 S 值取低半区:ECDSA 签名中的 S 必须至多为曲线阶的一半,把 S 限制在其低半取值范围;
  6. 不许留多余栈元素:scriptPubKey 求值结束时栈上必须只剩单个非零值;留下任何额外数据元素,脚本求值为假;
  7. CHECKMULTISIG 的占位元素须为空:OP_CHECKMULTISIG 与 OP_CHECKMULTISIGVERIFY 消耗的那个(不必要的)额外栈元素必须为空字节数组(OP_0 的结果),否则脚本求值为假。

原文还附了三组参考细则:低 S 值的具体范围与把高 S 换算为 S′ = 曲线阶 − S 的方法;DER 编码的逐字节格式(并指出该规则自 0.8.0 起已作为中继策略执行、只是还不是共识规则,与低 S 要求结合后签名总长至多 72 字节);压栈操作的最短形式对照表(空序列用 OP_0、0x01–0x10 用 OP_n、0x81 用 OP_1NEGATE、76–255 字节用 OP_PUSHDATA1、256–520 字节用 OP_PUSHDATA2、OP_PUSHDATA4 永不使用)以及数字最短编码的区间表。

4.2 引入方式:v3 区块与 v3 交易

新规则随 v3 区块与 v3 交易一同引入(交易跳过 v2,是为与区块规则的版本号保持同步;v2 交易与 v1 交易同等对待)。机制与 BIP-34 相同:

4.3 兼容性设想

原文的兼容性一节包括:新版节点软件使 v3 交易成为标准交易,并在其 scriptSig 满足上述规则时中继它们;v1 交易的中继不受影响,花费 v3 交易输出的 v1 交易也不受影响。钱包方面:v3 交易当时尚非标准,不能立即开始使用;应等网络中相当一部分节点升级到兼容代码后再启用。v3 的含义是“我想让这笔交易免受可锻性影响”,是否使用由钱包软件选择。

五、谁必须动

普通持币人:本提案从未部署,无需任何动作。按原文设想,将来即便启用,是否使用 v3 交易也是钱包层面的选择。

钱包开发者:设想中的职责是构造符合七条规则的 v3 交易(规范 DER、低 S、最小压栈、最短数字编码、干净的栈),并在网络升级比例足够前不抢先启用。

全节点与矿工:设想中需按 v3 区块的激活阈值执行新验证规则,并按新标准中继 v3 交易。

共识层:这是一次明确的共识规则收紧,涉及签名编码、脚本求值与区块/交易版本号。但它最终关闭,上述全部停留在设想层面。

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

状态为 Closed(已关闭)——不算数,从未部署。原文自己在篇首就声明它是进行中的草稿、未完成未实现;其价值在于把可锻性的来源清点得最全、把“共识规则能修到哪一步、修不到哪一步”划得很清楚。第 8、9 两项来源连作者本人都判定为共识规则修不了,这一点比七条规则本身更值得记住。

常见误读:

“BIP-62 曾经让比特币交易变得不可锻,后来才被撤销。”

不对。它从未生效过:文档自述未完成、未实现,档案状态是 Closed。可锻性在这份文档的年代主要靠策略层缓解——例如非 DER 签名自 v0.8.0 起不予中继、DER 要求先行作为中继策略执行——而不是靠这七条共识规则。把“有人提出过完整的共识方案”误记成“这套方案运行过”,是读这份文档最容易犯的错。

七、延伸

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