该文档提出了在 Elements 网络中 Taproot 升级时添加的新操作码,包括用于流式哈希的流式操作码、用于交易内省的交易内省代码、有符号 64 位算术操作码、转换操作码和新的加密操作符,旨在增强智能合约的功能和效率,同时考虑了资源限制和安全性。
本文档提议将新的操作码添加到 elements 网络以及 taproot 升级中。新的 tapscript OP_SUCCESS 操作码允许比通过 OP_NOP 更干净地引入新的操作码。在本文档中,我们提议修改以下 OP_SUCCESS 以具有额外的语义。我们按顺序使用操作码 OP_SUCCESS196,197...,以避免与 bitcoin 可能使用的 OP_SUCESSSx 发生冲突(假设 bitcoin 根据可用性按顺序使用这些操作码)。本文档的初始版本具有额外的操作码(OP_FOR,多字节操作码),但为了简化应用程序的复杂性,已更新为当前版本。
Taproot 已经极大地增加了 segwitv0 的资源限制,因此无需额外更改任何内容。特别是,根据 BIP 342
OP_CHECKSIG、OP_CHECKSIGVERIFY 或 OP_CHECKSIGADD)会将预算减少 50。如果这使预算低于零,则脚本会立即失败。80 字节。
用于流式哈希的流式操作码:由于 MAX_SCRIPT_ELEMENT_SIZE(520 字节) 的限制,我们无法对超过 520 字节的消息执行诸如 OP_SHA256 之类的哈希函数。这允许对超过 520 字节的数据进行哈希,同时仍然保持现有的针对资源耗尽攻击的安全性。Russell O'Connor 对此的提议可以在此处的描述中找到。
OP_SUCCESS196 定义为 OP_SHA256INITIALIZE,它弹出一个字节串,并通过将字节串添加到初始 SHA256 上下文中来 push SHA256 上下文。OP_SUCCESS197 定义为 OP_SHA256UPDATE,它首先弹出一个字节串,然后弹出另一个 SHA256 上下文,并通过将字节串添加到正在哈希的数据流来 push 更新后的上下文。OP_SUCCESS198 定义为 OP_SHA256FINALIZE,它首先弹出一个字节串,然后弹出另一个 SHA256 上下文,最后在添加字节串并完成填充后 push SHA256 哈希值。交易自省代码:通过使用 OP_CHECKSIGFROMSTACKVERIFY,已经可以在 elements 脚本中进行交易自省,但是,当前的解决方案在诸如 covenants 之类的应用程序中非常昂贵。因此,我们没有通过支持自省来添加任何新功能,只是使其更易于使用。与 covenants 一样,警告仍然相同,如果用户从交易中未签名的部分检查数据,则脚本可能会导致意外行为。
对于从 sighash 中未提交的数据部分进行检查的操作码,自省是安全的,因为对见证数据的任何更改都会导致 wtxid 发生更改,并且它将再次重新验证交易。对于 pegin 输入,资产/价值/脚本信息将来自父链。
OP_SUCCESS199 定义为 OP_INSPECTINPUTOUTPOINT:弹出一个 CScriptNum 输入索引 idx,并将 outpoint 作为元组 push。首先 push prev_out 的 txid(32),然后 push vout 的 4 字节,然后 push outpoint_flag(1),如 Elements 的修改版 BIP-341 SigMsg 中所定义。OP_SUCCESS200 定义为 OP_INSPECTINPUTASSET:弹出一个 CScriptNum 输入索引 idx,并将 nAsset 作为两个元素 push 到堆栈上。首先 push assetID(32),然后 push 前缀(1)。OP_SUCCESS201 定义为 OP_INSPECTINPUTVALUE:弹出一个 CScriptNum 输入索引 idx,并将 nValue 作为元组 push,值(8 字节 LE, 32) 后跟前缀(1)。OP_SUCCESS202 定义为 OP_INSPECTINPUTSCRIPTPUBKEY:弹出一个 CScriptNum 输入索引 idx,并根据 scriptPubkey 的类型 push 以下内容:
CScriptNum(-1) 以指示非原生的隔离见证 scriptPubKey。OP_SUCCESS203 定义为 OP_INSPECTINPUTSEQUENCE:弹出一个 CScriptNum 输入索引 idx,并将 nSequence(4) 作为小端数字 push。OP_SUCCESS204 定义为 OP_INSPECTINPUTISSUANCE:弹出一个 CScriptNum 输入索引 idx,如果资产有发行,则 push 资产发行信息,否则 push 一个空向量。资产发行信息按如下方式 push
nInflationKeys 作为元组 push,值(8 字节 LE, 32) 后跟 push 前缀(1)。如果 nInflationKeys 为 null,则 push 一个 8 字节 LE 的 0,后跟一个对于显式前缀(1)的 push。nAmount 作为元组 push,值(8 字节 LE, 32) 后跟 push 前缀(1)。如果 nAmount 为 null,则 push 一个 8 字节 LE 的 0,后跟一个对于显式前缀(1)的 push。assetEntropyassetBlindingNonceOP_SUCCESS205 定义为 OP_PUSHCURRENTINPUTINDEX,它将当前输入索引作为 CScriptNum push。这可以与输入自省操作码结合使用,以检查当前输入。OP_SUCCESS206 定义为 OP_INSPECTOUTPUTASSET:弹出一个 CScriptNum 输入索引 idx,并将 nAsset 作为元组 push,首先 push assetID(32),然后 push 前缀(1)。OP_SUCCESS207 定义为 OP_INSPECTOUTPUTVALUE:弹出一个 CScriptNum 输入索引 idx,并将 nValue 作为元组 push,值(8 字节 LE, 32) 后跟前缀。OP_SUCCESS208 定义为 OP_INSPECTOUTPUTNONCE:弹出一个 CScriptNum 输入索引 idx,并将 nNonce(33) push 到堆栈上。如果 nonce 为 null,则将一个空向量 push 到堆栈上。OP_SUCCESS209 定义为 OP_INSPECTOUTPUTSCRIPTPUBKEY:弹出一个 CScriptNum 输入索引 idx,并将 scriptPubkey push 到堆栈上。
CScriptNum(-1) 以指示非原生的隔离见证 scriptPubKey。OP_SUCCESS210 定义为 OP_INSPECTVERSION:将 nVersion(4) 作为小端 push。OP_SUCCESS211 定义为 OP_INSPECTLOCKTIME:将 nLockTime(4) 作为小端 push。OP_SUCCESS212 定义为 OP_INSPECTNUMINPUTS:将输入的数量作为 CScriptNum pushOP_SUCCESS213 定义为 OP_INSPECTNUMOUTPUTS:将输出的数量作为 CScriptNum pushOP_SUCCESS214 定义为 OP_TXWEIGHT:将交易权重 (8) 作为小端 push有符号 64 位算术操作码: 当前对 CScriptNum 的操作限制为 4 字节,并且由于最小化规则而难以组合。使用 8 字节有符号操作的固定宽度小端操作有助于对编码为 8 字节小端的金额进行计算。
CScriptNum 返回,结果是从顶部开始的第二个元素。如果操作溢出,则首先将操作数 push 到堆栈上,然后 push 成功位。[a_second a_top] 溢出,操作后的堆栈状态为 [a_second a_top 0],如果操作未溢出,则堆栈状态为 [res 1]。OP_IF\OP_ELSE 编写脚本来处理溢出,或者如果他们期望操作永远不会失败,则这使用户可以灵活地处理。
在定义可能失败的操作码时,我们只定义成功路径,并假设如上所述的溢出行为。
OP_SUCCESS215 定义为 OP_ADD64:弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。将 a + b push 到堆栈上。如果没有溢出,则 push 1 CScriptNum。 溢出行为如上所述。OP_SUCCESS216 定义为 OP_SUB64:弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。将 a - b push 到堆栈上。如果没有溢出,则 push 1 CScriptNum。 溢出行为如上所述。OP_SUCCESS217 定义为 OP_MUL64:弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。将 a*b push 到堆栈上。如果没有溢出,则 push 1 CScriptNum。 溢出行为如上所述。OP_SUCCESS218 定义为 OP_DIV64:弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。首先将余数 a%b(必须为非负数且小于 |b|)push 到堆栈上,然后将商 (a//b) push 到堆栈上。如果 b==0 或 a = -2<sup>63</sup> && b = -1,则视为溢出,如上所述。如果没有溢出,则 push 1 CScriptNum。OP_SUCCESS219 定义为 OP_NEG64:弹出第一个数字(8 字节 LE)作为 a,并将 -a push 到堆栈顶部。如果数字为 -2<sup>63</sup>(int64_min),则视为溢出,否则 push CScriptNum 1 以指示没有溢出。OP_SUCCESS220 定义为 OP_LESSTHAN64(不会失败!):弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。Push a < b。OP_SUCCESS221 定义为 OP_LESSTHANOREQUAL64(不会失败!):弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。Push a <= b。OP_SUCCESS222 定义为 OP_GREATERTHAN64(不会失败!):弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。Push a > b。OP_SUCCESS223 定义为 OP_GREATERTHANOREQUAL64(不会失败!):弹出第一个数字(8 字节 LE)作为 b,然后弹出另一个 a(8 字节 LE)。Push a >= b。OP_AND、OP_OR、OP_INVERT 和 OP_XOR 已经支持二进制运算转换操作码: 从 CScriptNum 转换为 8 字节 LE、4 字节 LE 的方法。
OP_SUCCESS224 定义为 OP_SCIPTNUMTOLE64:将堆栈弹出为最小的 CSciptNum,push 与该数字对应的 8 字节有符号 LE。OP_SUCCESS225 定义为 OP_LE64TOSCIPTNUM:将堆栈弹出为 8 字节有符号 LE。转换为 CScriptNum 并 push 它,失败则中止。OP_SUCCESS226 定义为 OP_LE32TOLE64:将堆栈弹出为 4 字节无符号 LE。Push 相应的 8 字节有符号 LE 数字。不会失败,对于版本、locktime、序列、输入数量、输出数量、权重等操作很有用。加密: 为了允许在 elements 上进行更复杂的操作,我们引入了以下新的加密操作符。每个操作码在 sigops 预算中计为 50。
OP_SUCCESS227 定义为 OP_ECMULSCALARVERIFY,它从堆栈中弹出三个元素,如下所述:1) 一个 32 字节的大端、无符号标量 k。2) 压缩的 EC 点 P,以及 3) 压缩的 EC 点 Q。如果 P、Q 无效或 k 不是 32 字节并且超出 secp256k1 曲线阶数,则中止。如果 Q != k*P,则中止。OP_SUCCESS228 定义为 OP_TWEAKVERIFY,具有以下语义:弹出以下三个元素:1) 32 字节的仅 X 内部密钥 P,2) 一个 32 字节的大端、无符号标量 k,以及 3) 33 字节的压缩点 Q。如果 P、Q 无效或 k 不是 32 字节并且超出 secp256k1 曲线阶数,则中止。如果 Q != P + k*G,其中 G 是 secp256k1 的生成器,则中止。对现有操作码的更改:
OP_CHECKSIGFROMSTACK 和 OP_CHECKSIGFROMSTACKVERIFY 以在见证程序为 v1 时遵循 bip340 的语义。更详细地说,操作码弹出三个元素堆栈 1) 32 字节的 pk 仅 X 公钥 2) 可变长度消息 msg 和 3) 64 字节的 Schnorr 签名 sig。令 res = BIP340_verify(pk, msg, sig),其中 BIP340_verify 被定义为 elements 在这里。如果操作码是 OP_CHECKSIGFROMSTACKVERIFY,如果验证失败,则中止。OP_CHECKSIGFROMSTACK,如果提供了一个空签名,则 push 0,如果验证成功,则 push 1。如果提供了未能通过验证的非空签名,则中止。OP_CHECKSIGFROMSTACK 和 OP_CHECKSIGFROMSTACKVERIFY 在 sigops 预算中都计为 50。OP_PUSHCURRENTINPUTINDEX 可以与 OP_INSPECTINPUTXX 结合使用,以获取有关堆栈上所花费输入的信息wtxid 中,因此无法进行自省。
- 原文链接: github.com/ElementsProje...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!