该BIP(Bitcoin Improvement Proposal)提议引入一种新的Taproot脚本公钥类型(SIGHASH_ANYPREVOUT),允许签名不绑定到特定的UTXO,从而使交易可以动态地绑定到具有兼容脚本的不同UTXO。这通过修改签名创建和验证中使用的交易摘要算法来实现,排除对先前输出的承诺,从而实现更灵活的链下协议和交易反应。
forked from bitcoin/bips
bip-anyprevout
搜索此仓库
/
复制路径
BlameMore file actions
BlameMore file actions
BIP118: tweak wording around 1-byte pubkey
Jul 2, 2021
d616d54 · Jul 2, 2021
打开提交详情
213 行 (151 loc) · 21.2 KB
/
顶部
预览
代码
Blame
213 行 (151 loc) · 21.2 KB
复制原始文件
下载原始文件
Outline
Edit and raw actions
BIP: 118
Layer: Consensus (soft fork)
Title: SIGHASH_ANYPREVOUT for Taproot Scripts
Author: Christian Decker <decker.christian@gmail.com>
Anthony Towns <aj@erisian.com.au>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0118
Status: Draft
Type: Standards Track
Created: 2017-02-28
License: BSD-3-Clause
Requires: 340, 341, 342
## Table of Contents<br>Permalink: Table of Contents<br>- Introduction <br> - Abstract<br> - Copyright<br> - Motivation<br>- Specification <br> <br> - Rules for signature opcodes<br> - Public key<br> - Signature message<br>- Security <br> <br> - Signature replay<br> - Malleability<br> - Privacy considerations<br>- Rationale<br>- Deployment<br>- Backwards compatibility<br>- Revisions<br>- Acknowledgements |
此 BIP 描述了 tapscript(BIP 342)交易的一种新型公钥。 它允许这些公钥的签名不提交到正在花费的确切 UTXO。 这使得交易可以动态绑定到不同的 UTXO,只要它们具有兼容的脚本。
本文档根据 3-clause BSD 许可证获得许可。
链下协议使用尚未广播到比特币网络的交易,以便重新协商应该在链上结算的最终状态。 在许多情况下,希望以另一种交易的形式,用预定的反应来响应在链上看到的给定交易。 通常,对于可能在链上看到的各种不同交易,都希望有相同的反应,但是由于响应交易中的输入签名会提交到正在反应的确切交易,这意味着必须为你希望能够响应的每笔可能的交易创建一个新的签名。
该提案引入了一种新的公钥类型[ 1],它通过排除对先前输出(以及,可选地,见证脚本[ 2]和值[ 3])的承诺,来修改签名创建和验证中使用的交易摘要算法的行为。 删除此承诺允许将已签名的交易动态地重新绑定到另一个需要相同密钥授权的先前输出。
由于使用了单独的公钥类型,因此动态重新绑定是选择加入,并且签名可以重新绑定的交易范围可以通过使用不同的密钥,将签名中的脚本提交,使用 UTXO 之间不同的金额,在消费交易中使用不同的 nSequence 值,或使用 codeseparator 操作码提交到脚本中的位置来进一步限制。
此 BIP 修改了BIP 342签名操作码[ 4](CHECKSIG
、CHECKSIGVERIFY
和 CHECKSIGADD
) 的行为,这些公钥的长度为 33 字节,第一个字节为 0x01
或精确到单字节向量 0x01
的公钥[ 5]。
这些密钥被称为 BIP 118 公钥。
Permalink: Rules for signature opcodes
BIP 342签名操作码的规则被修改,方法是从未知公钥类型列表中删除第一个字节为 0x01
且长度为 1 字节或 33 字节的密钥,并在处理未知公钥类型之前添加以下规则:
0x01
,或者如果公钥是 33 字节并且公钥的第一个字节是 0x01
,则它被认为是 BIP 118 公钥:
hash_type
值和如下定义的修改后的事务摘要来验证签名。要转换 1 字节的 BIP 118 公钥以与BIP 340一起使用,请使用BIP 341中定义的 32 字节 taproot internal key,p
。
要转换 33 字节的 BIP 118 公钥以与BIP 340一起使用,请删除 0x01
前缀并使用剩余的 32 字节。
函数 SigMsg118(hash_type, ext_flag) 计算被签名的消息作为字节数组,类似于BIP 341 中定义的 SigMsg(hash_type, ext_flag), SigExt118(hash_type,key_version) 计算扩展,类似于BIP 342。
参数 hash_type 是一个 8 位无符号值,重用BIP 341中定义的值,此外,值 0x41
、0x42
、0x43
、0xc1
、0xc2
和 0xc3
也对 BIP 118 公钥有效。
我们使用 hash_type
的位 6 和 7 定义以下常量:
SIGHASH_ANYPREVOUT = 0x40
SIGHASH_ANYPREVOUTANYSCRIPT = 0xc0
按照BIP 341的规定,参数 ext_flag 是 0-127 范围内的整数,用于指示扩展已添加到消息的末尾。参数 key_version 是一个 8 位无符号值(0-255 范围内的整数),用于提交到公钥版本。
以下限制适用,如果违反会导致验证失败:
SIGHASH_SINGLE
。如果未违反这些限制,则 SigMsg118(hash_type,ext_flag) 的计算结果为以下数据的串联,按顺序(每个项目的大小以字节列出)。2、4 或 8 字节项目中的数值以小端字节序编码。
SIGHASH_NONE
或 SIGHASH_SINGLE
:CTxOut
格式的所有输出的序列化的 SHA256。SIGHASH_ANYONECANPAY
:
COutPoint
(32 字节哈希 + 4 字节小端)。SIGHASH_ANYONECANPAY
或 SIGHASH_ANYPREVOUT
:
CTxOut
内的脚本。它的大小始终为 35 字节。SIGHASH_SINGLE
:CTxOut
格式的相应输出的 SHA256。类似地,SigExt118(hash_type,key_version) 的计算结果为以下各项的串联:
SIGHASH_ANYPREVOUTANYSCRIPT
:OP_CODESEPARATOR
的操作码位置,值采用小端格式(如果没有执行,则为 0xffffffff)。脚本中的第一个操作码的位置为 0。无论被推送的数据的大小如何,多字节推送操作码都算作一个操作码。请注意,如果 hash_type & 0x40 为零,则 SigMsg118(hash_type,ext_flag) == SigMsg(hash_type,ext_flag),并且 SigExt118(hash_type,0x00) == ext(其中 ext 是BIP 342中定义的消息扩展)。
要验证 BIP 118 公钥 p 的签名 sig:
与BIP 342签名验证的主要区别在于:
key_version
都设置为常量值 0x01
而不是 0x00
。[ 6]SIGHASH_ANYPREVOUT
,则计算摘要,就好像设置了 SIGHASH_ANYONECANPAY
,除了 outpoint
不包含在摘要中。SIGHASH_ANYPREVOUTANYSCRIPT
,则计算摘要,就好像设置了 SIGHASH_ANYONECANPAY
,除了 outpoint
、scriptPubKey
和 tapleaf_hash
不包含在摘要中。根据设计,与 SIGHASH_ALL
和 SIGHASH_ANYONECANPAY
签名相比,SIGHASH_ANYPREVOUT
和 SIGHASH_ANYPREVOUTANYSCRIPT
引入了额外的签名重放可能性(即它们允许在不同的交易中重复使用相同的签名)。
SIGHASH_ALL
和 SIGHASH_ANYONECANPAY
签名都通过提交到一个或多个输入来防止签名重放,因此只有在同一个输入可以多次花费的情况下才可能重放签名,这在比特币区块链上是不可能的(由于强制执行 BIP 30)。
使用 SIGHASH_ANYPREVOUT
签名,对于具有相同 scriptPubKey
和相同值的不同 UTXO,签名重放是可能的,而使用 SIGHASH_ANYPREVOUTANYSCRIPT
,对于在其潜在脚本之一中重复使用相同 BIP 118 公钥的任何 UTXO,签名重放是可能的。
因此,实施者必须确保仅在签名重放不会导致资金损失时(例如,由于协议的其他功能或交易的其他约束),或者当这种资金损失是可以接受的时,才重复使用 BIP 118 公钥。
使用 SIGHASH_ANYPREVOUT
或 SIGHASH_ANYPREVOUTANYSCRIPT
可能会引入额外的可延展性向量。
特别是,仅使用 ANYPREVOUT 签名进行身份验证的交易对于任何能够提供由签名满足的替代输入的人来说都是可延展的——以这种方式更改的输入将产生一个新的有效交易,支付给相同的接收者,但具有不同的 txid。 根据输入的更改,这可能会与原始交易冲突(如果某些输入仍然共享),或者可能会导致对接收者的双重支付(如果他们不这样做)。
此外,对于使用相同的 scriptPubKey
和值的一系列交易,并且仅通过 ANYPREVOUT 签名进行身份验证(如 eltoo 为失败案例所设想的那样),任何第三方都可能延展交易(及其 txid),而无需访问任何私钥,特别是通过省略中间交易。
这种形式的延展可以通过子交易也使用 ANYPREVOUT 签名来解决——当父交易被延展时,可以调整其子交易以引用新的 txid 作为输入,并且 ANYPREVOUT 签名仍然有效。
但是,如果子交易的输入以这种方式被延展,则由 SIGHASH_ALL
或 SIGHASH_ANYONECANPAY
签名授权的子交易将需要新的签名。
可以通过在使用 ANYPREVOUT 签名通过 SIGHASH_ALL
或 SIGHASH_ANYONECANPAY
授权的 UTXO 之前使用 BIP 68/BIP 112 相对时间锁来稍微减轻这种风险:相对时间锁可以确保输入具有足够的确认数,以至于它们只能在发生大型区块重组的情况下被替换。
请注意,此方法有缺点:相对时间锁会阻止通过子支付父级来提高费用,并且具有明显的缺点,即在时间锁到期之前,资金暂时无法使用。
Permalink: Privacy considerations
预计在实践中,ANYPREVOUT 签名将很少使用。 协议和钱包设计者应尽可能地使他们的交易使用 Taproot 密钥路径花费,这既是出于交易权重较低的效率原因,也是出于隐私原因,以避免第三方能够将他们的交易与其他协议的交易区分开来。
因此,确实使用 ANYPREVOUT 签名的交易将揭示有关该交易的信息,可能包括合作是不可能的,或者使用了什么协议或软件(由于脚本的详细信息)。
为了最大限度地提高隐私,因此建议协议设计者仅在将使用至少一个 ANYPREVOUT 签名花费的脚本中使用 BIP 118 公钥,并在 taproot merkle 树中使用密钥路径花费或备用脚本用于任何可以未经 ANYPREVOUT 签名授权的花费。 遵循此建议可能需要额外的脚本分支,这可能意味着在某些情况下,无视此建议可能会导致成本和隐私之间更好的权衡。
^ 为什么是新的公钥类型? 可以通过指定BIP 342中指定的_未知公钥类型_的新规则,在软分叉中引入用于 tapscript 的新公钥类型,因为这只需要对预先存在的签名操作码添加限制。 可能的替代方法是定义新的脚本操作码,使用不同的 taproot 叶版本,或使用与BIP 341指定的不同的 SegWit 输出集;但是,所有这些方法都更加复杂,最好为其他需要实际额外灵活性的升级保留。 在这种情况下,我们指定一个新的交易摘要,但保留相同的椭圆曲线和签名算法(即,secp256k1 和BIP 340)。
^ 为什么(以及为什么不)提交到见证脚本?
eltoo 论文提供了一个示例,说明为什么提交到见证脚本并不总是合适的。
它使用脚本和交易 nLockTime
使签名不对称,以便具有较早签名的交易可以由具有较晚签名的交易花费,但具有较晚签名的交易不能由具有较早签名的交易花费。
因此,第三个甚至更晚的交易的单个签名必须能够花费先前的两个交易,即使它们具有不同的 tapscript。
另一方面,这些情况也提供了充分的理由来选择提交到脚本:因为每个交易都有一个新的脚本,提交到脚本允许你生成一个精确应用于其中一个交易的签名。
在 eltoo 情况下,这允许你拥有一个更新交易的签名,该签名可以应用于任何先前的更新,以及一个仅应用于相应更新交易的结算交易的签名,同时对两者使用相同的密钥,这反过来允许更紧凑的脚本。
^ 为什么(以及为什么不)提交到输入值? 提交到输入值可能会提供额外的安全性,即签名不能被恶意重用来声明签名者不打算花费的资金,因此默认情况下,提交到输入值似乎是明智的。但是,这样做会阻止能够使用单个签名将一组具有相同花费条件的 UTXO 合并到单个 UTXO 中,这对于某些协议可能很有用,例如使用 eltoo 的分层承诺的提案。
^ 密钥路径花费呢? 本提案仅支持通过脚本路径花费的 ANYPREVOUT 签名,不支持密钥路径花费的 ANYPREVOUT 签名。 这是出于两个原因:首先,不支持密钥路径花费允许本提案独立于BIP 341 和BIP 342中包含的核心更改;其次,它允许地址选择加入或退出 ANYPREVOUT 支持,同时在花费之前保持无法区分。
^ 使用 0x01 公钥类型
因为 OP_0
在堆栈上留下一个空向量,所以它不满足BIP 342的未知公钥类型的规则。因此,使用 OP_1..OP_16
或 OP_1NEGATE
之一作为引用 taproot 内部密钥的方式很方便。
为了尽可能简单,我们使用第一个,并添加相同的字节作为前缀,以允许显式指定密钥的 ANYPREVOUT 签名。
^ 为什么要更改 key_version? 更改 key_version
确保如果使用相同的私钥生成 BIP 342 密钥和 BIP 118 公钥,则 BIP 342 密钥的签名对于 BIP 118 公钥(反之亦然)也无效。
TODO
可以与BIP 340、BIP 341 和BIP 342的部署同时或之后,将其部署为软分叉。
Permalink: Backwards compatibility 作为一个软分叉,旧的软件将继续运行而无需修改。 没有升级以支持 BIP 341 的节点会将所有 taproot witness programs 视为 anyone-can-spend 脚本,而升级以支持 BIP 341 和 BIP 342 但不支持 BIP 118 的节点,会将任何针对 BIP 118 公钥的非空签名视为有效。 因此,强烈建议节点进行升级,以便完全验证新公钥类型的签名。
未升级的钱包可以使用 SegWit version 0 programs、传统的 pay-to-pubkey-hash 等,从非升级和升级的钱包接收和发送比特币。 根据实现的不同,如果未升级的钱包支持发送到 BIP350 Bech32m 地址,并且不会因为认为输出不标准而阻止交易广播,则可能能够发送到 SegWit version 1 programs。
除了基于 Taproot 而不是 SegWit v0 之外,此 BIP 的主要区别在于:
SIGHASH_ANYPREVOUT
或 SIGHASH_ANYPREVOUTANYSCRIPT
签名花费。scriptPubKey
或 redeem/witness script 提交到 output 的花费条件。当使用 SIGHASH_ANYPREVOUTANYSCRIPT
时,此行为得以保留,但当使用 SIGHASH_ANYPREVOUT
时,签名现在会提交到 scriptPubKey
和 tapscript。SIGHASH_ANYPREVOUT
时,此行为得以保留,但当使用 SIGHASH_ANYPREVOUTANYSCRIPT
时则不然。OP_CODESEPARATOR
将影响 SIGHASH_ANYPREVOUT
和 SIGHASH_ANYPREVOUTANYSCRIPT
签名,而在之前的草案中则不会。SIGHASH_NOINPUT
标志最初由 Joseph Poon 在 2016 年 2 月 提出,此前 Joseph Poon 和 Thaddeus Dryja 在最初的 Lightning paper 中提到了它。
本文档是与许多人讨论的结果,并得到了 Greg Maxwell、Jonas Nick、Pieter Wuille 等人的直接投入。
- 原文链接: github.com/ajtowns/bips/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!