作者:Russell O’Conner

来源:https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-January/019813.html

回顾一下 CTV 和 ANYPREVOUT(APO) 之间的关系:

众所周知,由 CTV 和 ANYPREVOUT 开启的应用有很大一部分重叠,虽然它们俩的主打应用(CTV 的 “堵塞控制” 和 ANYPREVOUT 的 eltoo 闪电通道)有非常大的区别。尤其是,ANYPREVOUT 可以开启 CTV 的大部分应用,只是成本更高。CTV 的主要功能是允许一个脚本公钥(scriptPubKey)承诺可以花费它的交易的哈希值,而这个哈希值无需涵盖交易输入的 TXID。不涵盖输入的 TXID 的设计是必要的,因为输入的 TXID 也承诺了输入的脚本公钥,所以包含 TXID 会导致哈希承诺的循环(译者注:即,为了得出脚本公钥,必须知道未来交易的哈希值;但是为了得出这个哈希值,又必须先知道脚本公钥),因此是不可能构造出来的。另一方面,APO 为了实现其可重绑定签名(rebindable signatures)的目标,定义了一种签名哈希模式,也类似地排除了输入的 TXID(译者注:指签名无需涵盖输入的 TXID)。

这意味着,APO 可以模拟 CTV 的大部分属性,办法是让脚本公钥承诺一个公钥及其一个 APO 签名。实际上,比特币当前无法实现限制条款(covenant)的唯一原因就是在所有的 sighash 模式中,签名都涵盖了输入的 TXID,从而无法避免脚本公钥与 TXID 的循环。

通过 APO 来模拟的 CTV 功能,与真正的 CTV 提议的主要区别在于:(1)模拟 CTV 的成本。使用 CTV,只需一条 32 字节的哈希值就可以承诺花费交易;而使用 APO 来模拟它则需要 64 字节(一个签名),加上 32 字节(一个公钥),再加上少数用作标签的字节。可以通过使用内部公钥(只需 1 字节)来节省部分成本;而且,如果我们有 CAT 操作码的话,也许可以通过从可复用的片段中组装签名(即,将被承诺的签名的 nonce 设为等于公钥)来节约成本。

另一个主要的区别在于:(2)CTV 的交易哈希值涵盖了例如交易的输入的数量以及它们的 sequence 数值,而 APO 并没有涵盖这些。CTV 的哈希值包含了足够多的信息,从而,当我们将它与省略的 TXID 相结合,你就可以计算出花费交易的 TXID。尤其是,如果输入的数量被承诺为 1,一旦这个脚本公钥的 TXID 被知晓和承诺到区块链,其花费交易的 TXID 也就可以推导出来;而如果这笔花费交易也有 CTV 输出,花费这些输出的交易的 TXID 也可以进一步推导出来。虽然这属于微不足道的特性,但它是 APO 无法模拟出来的东西;人们举出的它的主要用途,是使用堵塞控制功能来为闪电通道注资,从而在这些通道实际得到区块链确认之前确定它们的 TXID 。但是,如果要用 APO 来模拟 CTV 的话,那么很可能人们会使用 eltoo 通道,而提前知晓 eltoo 通道的 TXID 是不必要的。

一种替代性的提议:

给定 CTV 和 APO 在功能上的重叠,我认为,将它们的操作分解成其组成部分、并以程序来重新组装这些成分的行为,是有意义的。为此,我提议以 OP_TXHASH 和 OP_CHECKSIGFROMSTACKVERIFY(CSFS)来替代它们。

OP_TXHASH 会从堆栈中弹出一个 txhash 标签,并根据这个标签计算一个(带标签的)哈希值,然后将结果推入栈中。

OP_CHECKSIGFROMSTACKVERIFY 将弹出一个公钥、一条消息、一个签名,如果签名验证失败,就出错退出。

CTV 和 TXHASH 有基本上相同的功能。 CTV DROP 可以用 <ctv_style_flag> TXHASH EQUALVERIFY 模拟出来。反过来也成立, <ctv_style_flag> TXHASH 可以用 <ctv-result-from-witness-stack> CTV 模拟出来。但是,如你所见,用 CTV 来模拟 TXHASH 比反过来更加昂贵,因为最终的 32 字节的哈希值必须包含在见证数据内。

<anyprevout-pubkey> CHECKSIGVERIFY 可以用 <apo_style_flag> TXHASH <pubkey> CHECKSIGFROMSTACKVERIFY 模拟出来。从这里我们就可以看出无需给堆栈推入哈希值的优势。不需要在见证数据中包含结果哈希值的拷贝,就可以模拟出 APO。

除了 CTV 和 APO 的应用,有了 CSFS,我们就可以验证断言机(oracle)对任意消息的签名。从中可以看出将这些操作分解为元件的好处。通过给予用户从元素中编程自己的应用场景的能力,我们只需更少的操作码就能得到更多的应用。

声明:

首先,我知道复制 CTV 和 APO 的行为比起它们自身(作为定制化的专用提议),会消耗多一些字节。但这是我们选择从碎片编程解决方案所需付出的代价。而我们成功获得了从这些碎片开发更多应用的好处。

不像 CTV,TXHASH 不能兼容 NOP(译者注:指预留的、不会触发脚本运算器任何操作的 “NO_OP” 操作码),所以只能在 tapscript 中实现。特别是,裸 CTV(bare CTV)是无法用 TXHASH 实现的。但是,我的这个提议并不预先排除了为传统脚本加入 CTV、同时为 tapscript 加入 TXHASH 的可能性。

出于类似的原因,TXHASH 也无法顺从地延伸到未来会出现的 txflag 集合。理论上来说,你可以让 TXHASH 在遇到未知的标签时以成功状态终止(abort-with-success)。但是,这会让 tapscript 的分析变得难得多。Tapscript 将变成会根据脚本片段的组装和执行的顺序而成功或失败,从而,顺序出错了就将无可挽回。这样的行为明显不同于当前的 OP_SUCCESS 操作码群体的行为,它们只会根据存在与否(会不会被执行)而成功或失败。

我认为,升级 TXHASH 的难点,可以通过在一开始设计一个强健的 TXHASH 标签集合来缓解。例如,使用比特来控制是否涵盖:(1)交易版本号;(2)锁定时间;(3)txid;(4)sequence 数字;(5)输入的数额;(6)输入的脚本公钥;(7)输入的数量;(8)输出的数额;(9)输出的脚本公钥;(10)输出的数量;(11)tapbranch;(12)tapleaf;(13)opseparator 输出;(14)涵盖全部输入,或不涵盖全部、某个输入;(15)涵盖全部输出,或不涵盖全部、某个输出;(16)某个输入的位置;(17)某个输出的位置;(18)SIGHASH 标签(不论是否涵盖,这个选择都必须指定)。也许可以指定在某一种情况下应该涵盖哪个输入或输出的位置,以及输出和输入的位置是否应相互关联,还是放在绝对的位置。

也就是说,即使未来需要加入其它 txhash 标签模式,添加 TXHASH2 也总是一种办法。

与未来可能的操作码的交互:

我们应该稍微考虑一下这些操作码如何与未来的操作码(例如 CAT、滚动 SHA256 操作码)互动,以及它们如何跟其它可能做到类似事情的限制条款操作码、(已经添加到 Elements 项目的)为了计算目的而将输入或输出的数额直接推入堆栈的操作码互动。

有了 CAT 以及/或者 滚动 SHA256 操作码 以及/或者 现有的 SHA256 操作码,CSFS 可以验证由程序组装出来的消息的签名。同样地,结合对 TXHASH 的多次调用,可以用来创建承诺了交易数据的复杂子集的签名。

如果有新的操作码,可以将交易的部分数据直接推入堆栈(例如 OP_INSPECTOUTPUTVALUE),可能需要担心 TXHASH 会因此被淘汰,因为,如果有滚动 SHA256 操作码,就可以模拟出 TXHASH。但是,给定 TXHASH 可以紧凑地创建出大部分交易数据的一个哈希值,TXHASH 被废弃的可能性似乎不大。类似地,结合 TXHASH 和交易内省操作码,可以用来开发 “减法限制条款”。

常见的开发限制条款的方法,我们称为 “加法限制条款”,是将你希望固定的交易的部分数据都推入堆栈,哈希它们,然后验证结果与一个固定的数值相匹配。另一种办法,可以称为 “减法限制条款”,是将所有你希望保持自由的部分推入堆栈,然后用滚动 SHA256 操作码从一个固定的中间状态(承诺了交易哈希数据的一个前缀)开始。自由的部分会被哈希到这个中间状态。最后,验证最终的哈希值跟 TXHASH 所返回的哈希值相匹配。这种能力将可以基于 TXHASH 哈希值的构造方式的细节、开发出减法限制条款,我听说 CTV 已经考虑过这个问题。

(完)