该文档详细描述了 Taproot 脚本验证的语义,包括对签名操作码的修改、多重签名策略的实现、以及资源限制的变化等。Tapscript通过软分叉进行升级,并引入了OP_SUCCESS操作码以实现更简洁的新操作码引入方式,旨在改进比特币脚本系统的灵活性和效率。
forked from bitcoin/bips
bip-anyprevout
搜索此仓库
/
复制路径
BlameMore 文件操作
BlameMore 文件操作
合并 pull request bitcoin#1104 来自 ajtowns/202103-bip341-speedy-tri…
打开提交详情
Apr 25, 2021
40b10c8 · Apr 25, 2021
打开提交详情
146 行 (113 loc) · 23.3 KB
/
顶部
146 行 (113 loc) · 23.3 KB
复制原始文件
下载原始文件
大纲
编辑和原始操作
BIP: 342
Layer: Consensus (soft fork)
Title: Validation of Taproot Scripts
Author: Pieter Wuille <pieter.wuille@gmail.com>
Jonas Nick <jonasd.nick@gmail.com>
Anthony Towns <aj@erisian.com.au>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0342
Status: Draft
Type: Standards Track
Created: 2020-01-19
License: BSD-3-Clause
Requires: 340, 341
Post-History: 2019-05-06: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-May/016914.html [bitcoin-dev] Taproot proposal
## 目录<br>固定链接:目录<br>- 简介 <br> - 摘要<br> - 版权<br> - 动机<br>- 设计<br>- 规范 <br> - 脚本执行<br> - 签名操作码规则<br> - 签名验证<br> - 资源限制<br>- 原理<br>- 部署<br>- 示例<br>- 致谢 |
本文档规定了在 BIP341 下的初始脚本系统的语义。
本文档采用 3-clause BSD 许可。
BIP341 仅对脚本结构提出了改进,但其某些目标与脚本语言本身中某些操作码的语义不兼容。 虽然可以在单独的可选改进中处理这些问题,但除非与 BIP341 本身同时解决,否则无法保证其影响。
具体来说,目标是使 Schnorr 签名、批量验证和 签名哈希 改进也可用于使用脚本系统的花费。
为了实现这些目标,签名操作码 OP_CHECKSIG
和 OP_CHECKSIGVERIFY
被修改为验证 BIP340 中指定的 Schnorr 签名,并使用基于 BIP341 中通用消息计算的签名消息算法。
tapscript 签名消息还简化了 OP_CODESEPARATOR
处理并使其更有效。
效率低下的 OP_CHECKMULTISIG
和 OP_CHECKMULTISIGVERIFY
操作码被禁用。
相反,引入了一个新的操作码 OP_CHECKSIGADD
,以允许以可批量验证的方式创建相同的多重签名策略。
Tapscript 使用了一种新的、更简单的签名操作码限制,修复了与交易权重复杂的交互。
此外,通过要求 MINIMALIF,消除了潜在的可延展性向量。
Tapscript 可以通过定义未知的密钥类型通过软分叉进行升级,例如添加新的 hash_types
或签名算法。
此外,新的 tapscript OP_SUCCESS
操作码允许比通过 OP_NOP
更干净地引入新的操作码。
以下规则仅在验证满足以下所有条件的交易输入时适用:
对此类输入的验证必须等同于按指定顺序执行以下步骤。
OP_SUCCESS80
、...、OP_SUCCESS254
,统称为 OP_SUCCESSx
[ 1]。OP_SUCCESSx
绕过此检查。CastToBool()
计算结果为 true,则失败。tapscript 的执行规则基于 BIP141 中 P2WSH 的执行规则,包括 BIP65 和 BIP112 中定义的 OP_CHECKLOCKTIMEVERIFY
和 OP_CHECKSEQUENCEVERIFY
操作码,但有以下修改:
OP_CHECKMULTISIG
和 OP_CHECKMULTISIGVERIFY
[ 2]。 禁用的操作码的行为方式与 OP_RETURN
相同,即在执行时立即失败并终止脚本,并且在脚本的未执行分支中找到时会被忽略。OP_IF
和 OP_NOTIF
操作码的输入参数必须正好是 0(空向量)或正好是 1(值为 1 的单字节向量)[ 3]。OP_SUCCESSx
,并使脚本无条件有效。OP_CHECKSIG
和 OP_CHECKSIGVERIFY
被修改为对 Schnorr 公钥和签名(参见 BIP340)而不是 ECDSA 进行操作,并添加了一个新的操作码 OP_CHECKSIGADD
。
以下规则适用于 OP_CHECKSIG
、OP_CHECKSIGVERIFY
和 OP_CHECKSIGADD
。
OP_CHECKSIGVERIFY
和 OP_CHECKSIG
,公钥(顶部元素)和签名(顶部第二个元素)从堆栈中弹出。
OP_CHECKSIGADD
,公钥(顶部元素)、CScriptNum
n
(顶部第二个元素)和签名(顶部第三个元素)从堆栈中弹出。
n
大于 4 个字节,则脚本必须失败并立即终止。OP_CHECKSIGVERIFY
,脚本必须失败并立即终止。OP_CHECKSIG
,一个空向量被推送到堆栈上,并且执行继续执行下一个操作码。OP_CHECKSIGADD
,一个值为 n
的 CScriptNum
被推送到堆栈上,并且执行继续执行下一个操作码。OP_CHECKSIGVERIFY
,执行继续进行,而不会对堆栈进行任何进一步的更改。OP_CHECKSIG
,一个 1 字节的值 0x01
被推送到堆栈上。OP_CHECKSIGADD
,一个值为 n + 1
的 CScriptNum
被推送到堆栈上。要使用公钥 p 验证签名 sig:
OP_CODESEPARATOR
的操作码位置,值为小端字节序(或者如果未执行,则为 0xffffffff)。 脚本中的第一个操作码的位置为 0。 多字节 push 操作码计为一个操作码,无论正在推送的数据的大小如何。 已解析但未执行的分支中的操作码也计入此值。总之,签名验证的语义与 BIP340 相同,除了以下几点:
OP_CODESEPARATOR
的影响。OP_CODESEPARATOR
的操作码位置。[ 8]除了更改许多操作码的语义之外,资源限制也进行了一些更改:
CompactSize
前缀)。 使用非空签名执行签名操作码(OP_CHECKSIG
、OP_CHECKSIGVERIFY
或 OP_CHECKSIGADD
)会将预算减少 50。如果这使预算低于零,则脚本会立即失败。 具有未知公钥类型和非空签名的签名操作码也会被计算在内。[ 11][ 12][ 13]。^ OP_SUCCESSx
OP_SUCCESSx
是一种升级脚本系统的机制。 在软分叉定义其含义之前使用 OP_SUCCESSx
是不安全的,并且会导致资金损失。 在脚本中包含 OP_SUCCESSx
将无条件地传递它。 它优先于任何脚本执行规则,以避免在指定各种边缘情况时遇到的困难,例如:输入堆栈大于 1000 个元素的脚本中的 OP_SUCCESSx
,在太多签名操作码之后的 OP_SUCCESSx
,甚至是没有缺少 OP_ENDIF
的条件语句的脚本。 脚本中任何位置存在的 OP_SUCCESSx
都会保证所有这些情况都能通过。 OP_SUCCESSx
类似于早期比特币版本(v0.1 到 v0.3.5,包括 v0.3.5)中的 OP_RETURN
。 原始的 OP_RETURN
立即终止脚本执行,并根据终止时顶部堆栈元素返回 pass 或 fail。 这是原始比特币协议中的一个主要设计缺陷,因为它允许通过将 OP_RETURN
放入 scriptSig
中进行无条件的第三方盗窃。 这在当前提案中不是一个问题,因为第三方不可能将 OP_SUCCESSx
注入到验证过程中,因为 OP_SUCCESSx
是脚本的一部分(因此由 taproot 输出提交),这意味着币所有者的同意。 OP_SUCCESSx
可用于各种升级可能性:
OP_SUCCESSx
转换为功能性操作码。 与只能对堆栈进行只读访问的 OP_NOPx
派生的操作码不同,OP_SUCCESSx
也可以写入堆栈。 对包含 OP_SUCCESSx
的脚本的任何规则更改都可能只会将有效的脚本变为无效的脚本,并且这始终可以通过软分叉实现。OP_SUCCESSx
优先于初始堆栈和 push 操作码的大小检查,因此需要大于 520 字节的堆栈元素的 OP_SUCCESSx
派生操作码可能会在软分叉中提升限制。OP_SUCCESSx
还可以重新定义现有操作码的行为,以便它们可以与新操作码一起使用。 例如,如果 OP_SUCCESSx
派生的操作码使用 64 位整数,它也可能允许 同一脚本 中的现有算术操作码执行相同的操作。OP_SUCCESSx
甚至会导致可能无法解析的脚本通过,因此它可以用于引入多字节操作码,甚至是全新的脚本语言,并在前面加上特定的 OP_SUCCESSx
操作码。OP_CHECKMULTISIG
和 OP_CHECKMULTISIGVERIFY
,而不是将它们转换为 OP_SUCCESSx? 这是一种预防措施,以确保意外地在 Tapscript 中继续使用 OP_CHECKMULTISIG
的人立即注意到问题。 这也避免了脚本反汇编程序需要成为上下文相关的复杂性。OP_CHECKSIGADD
添加此操作码是为了补偿与批量验证不兼容的 OP_CHECKMULTISIG
类操作码的丢失。 OP_CHECKSIGADD
在功能上等同于 OP_ROT OP_SWAP OP_CHECKSIG OP_ADD
,但仅占用 1 个字节。 OP_ADD
的所有与 CScriptNum
相关的行为也适用于 OP_CHECKSIGADD
。CHECKMULTISIG
的替代方案 有多种使用 Taproot 和 Tapscript 实现 k-of-n 阈值策略的方法:
OP_CHECKSIGADD
的脚本 一个带有见证 0 <signature_1> ... <signature_m>
的 CHECKMULTISIG
脚本 m <pubkey_1> ... <pubkey_n> n CHECKMULTISIG
可以被重写为带有见证 <w_n> ... <w_1>
的脚本 <pubkey_1> CHECKSIG <pubkey_2> CHECKSIGADD ... <pubkey_n> CHECKSIGADD m NUMEQUAL
。每个见证元素 w_i
都是对应于 pubkey_i
的签名或者一个空向量。一个类似的 CHECKMULTISIGVERIFY
脚本可以通过将 NUMEQUAL
替换为 NUMEQUALVERIFY
来翻译为 BIP342。这种方法与现有的基于 OP_CHECKMULTISIG
的脚本具有非常相似的特性。<pubkey_1> CHECKSIGVERIFY ... <pubkey_(n-1)> CHECKSIGVERIFY <pubkey_n> CHECKSIG
实现一个 k-of- k 策略。出于隐私原因,这可能比前一种方法更可取,因为它只暴露了参与的公钥,但只有在 k 值较小的情况下才更具成本效益(对于任何 n 都是 1-of- n,对于 n ≥ 6 都是 2-of- n,对于 n ≥ 9 都是 3-of- n,以此类推)。此外,这里的签名提交到使用的分支,这意味着签名者需要知道哪些其他签名者将参与,或为每个树叶生成签名。SIGHASH
模式,以及 NOINPUT 标记的公钥 和一个公钥常量,该常量被 taproot 内部密钥替换以进行签名验证。OP_CODESEPARATOR
的位置? 这允许继续使用 OP_CODESEPARATOR
来签署脚本的已执行路径。由于 codeseparator_position
是哈希的最后一个输入,因此可以有效地缓存 SHA256 中间状态,以用于单个脚本中的多个 OP_CODESEPARATOR
。相比之下,BIP143 对 OP_CODESEPARATOR
的处理是仅从上次执行的 OP_CODESEPARATOR
开始提交到已执行的脚本,这需要不必要的脚本重新哈希。应该注意的是,通过在两个代码分支之间共享第一个公钥来节省脚本中第二个公钥推送的唯一已知 OP_CODESEPARATOR
用例,很可能可以通过将每个分支移动到单独的 taproot 叶子中来更便宜地表达。scriptCode
(仅通过可预先计算的 tapleaf 哈希间接包含),因此签名检查花费的 CPU 时间不再与正在执行的脚本的大小成正比。OP_IF
、OP_NOTIF
、OP_ELSE
和 OP_ENDIF
使用 O(1) 逻辑,如 此处 建议和 此处 实现,也可以避免唯一的其他实例。SIGHASH_ALL
)签名对组成,每个签名对具有 33 + 65 个权重单位(包括 1 个权重单位的 CompactSize
标签)。如果在脚本中重复使用公钥,情况也是如此,因为签名的权重本身就是 65 或 66 个权重单位。但是,该限制通过要求额外的权重来增加具有重复签名(和公钥)的异常脚本的费用。每个 sigop 因子 50 的权重对应于 BIP141 区块限制的比率:4 mega 权重单位除以 80,000 个 sigop。限制允许的“免费”签名操作码的存在是为了考虑交易输入中非见证部分的权重。OP_ROLL
(考虑到 1000 个堆栈元素限制)打包的脚本的成本。也就是说,该结构非常灵活,并且允许添加新的签名操作码,例如 CHECKSIGFROMSTACK
,以通过软分叉计入限制。即使将来引入了改变正常脚本成本的新操作码,也没有必要用毫无意义的数据填充见证。相反,可以使用 taproot 附件向见证添加权重,而无需增加实际的见证大小。此提案的部署方式与 Taproot ( BIP341) 相同。
Taproot ( BIP341) 测试向量还包含 Tapscript 执行的示例。
本文档是多次讨论的结果,并包含许多人的贡献。作者要感谢所有提供宝贵反馈和评论的人,包括 结构化评论 的参与者。
- 原文链接: github.com/ajtowns/bips/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!