作者:Shinobi

来源:https://bitcoinmagazine.com/print/the-core-issue-why-bitcoin-needed-a-remodel-with-segwit-and-taproot

“隔离见证(Segregated Witness)”(其 BIP 作者是 Pieter Wuile、Eric Lombrozo和 Johnson Lau)和 “Taproot”(其 BIP 作者是 Pieter Wuille、Jonas Nick、Tim Ruffing 和 Anthony Towns)是比特币协议迄今为止最大的两项变更。

前者在根本上改变了比特币交易的结构(并因此改变了比特币区块),以解决以往的交易结构的内在局限性。后者则重构了比特币的脚本编程语言的一些方面(构造和验证复杂脚本的方式),并加入了一种新的生成密码学签名的方案。

两者都属 巨大的 变更;相较之下,增加一个像 CHECKTIMELOCKVERIFY(CLTV)这样的操作码,只是允许收款方选择防止自己在特定时间点之前花费一笔支付,没什么大不了的。(译者注:CLTV 是脚本层面的相对时间锁,在 2015 年的 BIP65 软分叉中加入比特币协议。)

这些变更是为了解决比特币作为一个系统的最根本短板和局限性。作为一个维护比特币的整体状态(即所有未花费的钱币)的全局共识的基础层,比特币协议是一项价值不可估量的天才创新。但想让每个人都能直接与这些钱币交易,它还远远不能胜任。

在隔离见证和 Taproot 激活之后的这些年,它们解决的许多短板也已经被遗忘。而它们的设计抉择背后的这些理由和哲学,也随着时间推移在口口相传中逐渐歪曲。

这两项变更都是对比特币协议的大问题的解决方案,但它们也都为解决其它问题、未来作出其它优化,打下了基础。

值此许多新人加入比特币网络之时,值得回顾这两项变更,并叙述它们的设计抉择的上下文。

隔离见证(BIP 141 1

当一笔比特币交易花费一些钱币时,它会通过创建这些钱币的交易的标识符(TXID)、以及这些钱币在输出队列中的索引号,来索引这些钱币。这保证了交易的输出都可以唯一地标识,并且以绝对的确定性验证它们此前没有被花费过。

在隔离见证升级以前,比特币交易的结构是这样的:

[Version] [Inputs] [Outputs] [Locktime]
交易版本号	输入	输出	交易锁定时间

交易标识符是这些数据的一个哈希值。问题在于,输入的 “脚本签名(ScriptSig)”(签名、哈希值原像,等等),其作用是用来证明这笔交易(花费操作)是有效的,也被当成输入的一部分。你可以稍微改变一个脚本签名中的程序指令,甚至改变其中的密码学签名,都不会使它失效。

这些 “熔融操作” 会改变 TXID 。这就给预先签名的交易带来的大麻烦。

闪电网络、Ark、Spark、BitVM、谨慎日志合约(DLC),所有这些扩容工具都依赖于预先签名的交易。它们要求参与者先创建一笔待签名的注资交易、预先签名保证合约妥善执行和资金安全的所有交易,然后才签名和确认注资交易。所有这些系统,也都使用多签名的身份认证,来保证资金不会被重复花费(这一点很重要,我们后面还会提到)。

如果注资交易被熔铸了,并且它的交易 ID 在它得到区块确认之前就改变了,那么所有保护二层资金的预先签名的交易都会作废。如果在你的注资交易传播期间,任何人都能改变它的 TXID,那么上述所有工具都毫无用武之地。

隔离见证使用一个未定义的操作码作为一种遮掩,替换了以往放在输入的脚本签名中的数据,并将所有这些数据都移到了交易的一个新的叫做 “见证(witness)” 的字段中。新的交易结构是这样的:

[Version] [Marker/Flag] [Inputs] [Outputs] [Witness] [Locktime]
交易版本号		标记		输入		输出		见证		交易锁定时间

输入中的这个 “百叶窗”,让旧的节点(没有使用隔离见证规则的节点)可以默认把与它相关的东西都当成有效的,而新的节点(使用隔离见证规则的节点)则会时机应用相应的验证逻辑。传统意义上的 TXID,将不再因为见证中的数据改变而发生改变。这就为预先签名的交易解决了问题,并为今天得到开发的各种扩容解决方案开启了大门。

但是,区块头中的交易默克尔树仅仅承诺进入该区块的各交易的传统 TXID,这又产生了一个新问题:区块没有对见证数据的任何承诺。所以,我们需要见证承诺,以及 “见证交易 ID(WTXID)”。就跟常规的 TXID 的默克尔树构造一样,各交易的 WTXID 会形成一棵默克尔树,并将承诺放到 coinabse 交易的见证中。(译者注:应有误,WTXID 的默克尔树根应该是放在 coinbase 交易的一个输出的脚本公钥中的。)

唯一的区别在于,这棵树的树根是跟一个保留数值一起哈希的,并且这个保留数值会放在 coinbase 交易的见证中。这让这个数值在未来可用于承诺共识规则中的其它新数据字段。在这种见证树承诺(想法来自 Luke Dashjr)发明以前,人们以为隔离见证需要一次硬分叉 ,因为交易结构改变了、而且区块头中需要一个专门的见证承诺。

这种 “百叶窗” 设计,也让对脚本编程系统的任何升级都成为可能,因为所有新型的数据都会被不使用新规则的节点无视,也不会由它们验证。这允许我们设计一种新的脚本系统,绕过老式脚本系统的所有限制。这种升级路径的灵活性,也让集成 Schnorr 签名成为可能,并且允许我们加入抵抗量子计算的签名方案(如果有必要的话)(量子抗性签名方案的公钥体积一般都大于老式脚本对单个数据对象的 520 字节体积限制,签名也是如此)。

隔离见证解决了交易 ID 熔融性的根本问题,让可扩展的二层协议可以放开手脚,把比特币带给更多用户;但同时,它也为有必要支持和能够提升这些二层协议的任何脚本系统优化都打下了基础。

Schnorr 签名 2

“Schnorr 签名方案” 是 Claus Schnorr 在 1991 年发明的, 并且他马上就获得了专利。事实上,正是因为 Schnorr 签名有专利权,人们才发明了 ECDSA 签名方案。Schnorr 签名的专利在 2010 年 2 月过期,就在比特币网络启动的一年多以后。

如果没有那项专利,也许中本聪(以及世界上的其他人)一开始就会使用 Schnorr 签名。

相较 ECDSA,Schnorr 签名有几个主要优势:

  • Schnorr 签名是可证明安全的。证明 Schnorr 签名 不可伪造/无法打破的数学证据要更强,用到的假设也更少(相比 ECDSA)。让比特币的心脏中的密码学拥有更强的安全性保证,显然是一个巨大的好处。
  • Schnorr 签名是天然无法熔铸的,这就意味着,能够替换掉签名而不会使交易作废这样的问题,在使用 ECDSA 时会存在,在使用 Schnorr 签名却是完全不可能的。
  • Schnorr 签名拥有一种 “线段性”,允许简单且高效的加法密码构造、分布式密钥生成以及分布式签名生成。这让用户可以直接把单个的 Schnorr 公钥 “加起来”,然后作为一个团队,制作出这个聚合公钥的签名。

Schnorr 签名相比 ECDSA 更安全、无法被第三方熔铸,并且打开了大门,让我们可以用所有类型的高效而灵活的密码学方案来提升多签名的身份认证。

在前文讨论交易熔融性时,我提到,所有使用预先签名的交易的链外协议都依赖于多签名身份认证来保护用户的资金。这种做法是共享资金控制权时的安全措施,却隐含了由此带来的扩容效果的天花板。传统的多签名无法缩小。交易的体积本身面临限制;对于版本 0 的(隔离见证的)见证数据,其体积也有限制。如果一个多签名地址只能允许这么多参与者,那就暗含了只有这么多参与者能够分享对资金的控制权(因此为扩容效果带来了上限)。

基于 Schnorr 签名的签名方案通过聚合多个公钥为一个集体公钥,放宽了这个限制:从此我们不再需要构造出每个成员的公钥都显式包含在内的脚本。在隔离见证升级以前,一个多签名地址只能有 15 个参与者;在隔离见证之后,扩大的限制可以容纳 20 个参与者。

而使用 “MuSig”5 和 “FROST”6 这样的基于 Schnorr 的签名方案,这些限制完全不存在了(至少在共识规则层面是不存在了)。参与一个多签名装置的人群可以想要多大就有多大,只要这群人能够协调签名流程,不会因为总是有人拒绝签名或退出而无法完成签名。

(译者注:MuSig 为基于 Schnorr 的多重签名方案,每一个参与了公钥聚合的人都要参与签名;而 FROST 是一种阈值签名方案,参与签名的公钥数量只要达到预先设定的阈值就可以制作出签名。

同样的属性,既允许我们像这样聚合密钥,也允许实现高效的适配器签名(adaptor signatures):在这类方案中,我们可以制作出暂时无效、一旦某一段秘密信息暴露就会生效的签名。这些属性也让一些基于零知识证据的方案成为可能,签名人可以签名自己没有看到的消息。

Taproot 3 4

“Taproot” 是一种叫做 “默克尔化抽象语法树(MAST)” 7 的旧概念的升级版。MAST 自身只是 “支付到脚本哈希值(P2SH)” 脚本的一种插件 8。P2SH 的出现是为了处理两个大问题:

  • 在使用大体积的定制化锁定脚本时,(如果要将这样的脚本直接放在交易的输出中),产生的未花费输出会有更大的体积(相比于使用小体积的锁定脚本),也就需要更多空间来存储 UTXO 集(也就是比特币网络的最新状态)。
  • 在使用大体积的定制化锁定脚本时,发送者要支付更高的费用,因为 TA 发起的交易的体积更大,这会劝退人们给可能更安全的定制化脚本支付。

P2SH 的想法是,与其在交易的输出中显式地包含整个脚本,不如仅包含这样的脚本的一个哈希值;在花费这个输出时,再由输出的主人(前一笔的交易中的收款方)在输入中提供完整的脚本,可以用哈希值来验证。这就解决了未花费的输出占用存储空间的问题,并让使用较大体积脚本的经济负担由使用者自己承担(而不是让给他们支付的人来承担)。

不过,这里还留下了一个问题。定制化的脚本可能包含了多种花费方法,但是,在花费的时候,花费者依然需要揭晓整个脚本,其中也包含了对于验证本次花费操作有效性无关的脚本分支。因此,定制化脚本的空间效率会随着脚本的大小而不断下降,并且让花费者承担超出必要水平的代价。

MAST 背后的想法在于,我们可以将一个多分支脚本分拆为单个单个的花费条件,然后用这些花费条件构造出一棵默克尔树。每个花费条件都会经过哈希,而默克尔树的树根就是用户的地址。在花费的时候,用户只需提供自己用到的花费条件,以及证明该条件存在于树上的默克尔证据,然后是满足这个花费条件的必要数据。

这种默克尔树构造,不仅解决了 P2SH 尝试解决的所有问题,还优化了使用者的花费成本(同时提升了他们的隐私性!)。

Taproot 采用了这个概念,并且利用 Schnorr 签名的线段性、以更加保护隐私的方式集成了这个概念。在人们想要的绝大部分合约中,都有一个乐观结果,就是所有用户都对如何分割资金达成了一致。在这种情况下,他们可以直接签名交易。Taproot 使用 MAST 的根来 “微调” 一个 Schnorr 公钥,从而产生一个新的公钥;只需使用同一个 MAST 的根来 “微调” 私钥,就能得到这个新公钥的对应私钥。

这样一来,用户既可以使用这个调整后的密钥直接花费他们的输出、不留下其中存在一棵 MAST 的任何痕迹;也可以揭晓原本的公钥、MAST 树根以及一个存放在树上的花费条件。此外,如果你完全不希望直接使用调整后的密钥,还可以使用一个特殊的 NUMS(此中无后门)点作为原始公钥,这个点是可以证明无法花费的(没人知道它背后的私钥),从而只留下 MAST 上的脚本作为有效的花费路径。

除了利用隔离见证的设计抉择,Taproot 也引入了 “tapscript”,一种新的脚本编程系统。相比于以前的脚本编程系统,它的主要变化在于:放弃了 OP_CHECKMULTISIGOP_CHECKMULTISIGVERIFY(它们是原本用于验证多签名的操作码),代之以 OP_CHECKSIGADD,它可以更高效地验证多个签名。结合 Schnorr 密钥聚合,这就产生了跟老式脚本一样的多签名功能。

此外,tapscript 还将 OP_CHECKSIGOP_CHECKSIGVERIFY 修改成只能验证 Schnorr 签名,并加入了 OP_SUCESS 作为对 OP_NOP(老式脚本中的未定义操作码)的替代。OP_SUCCESS 被设计成允许更加干净、更加安全的操作码升级(相比 OP_NOP)。

见证数据体积限制

行文至此,还有两个方面没有得到讨论,那就是在隔离见证升级中加入的 “区块重量(blockweight)” 限制,以及在 Taproot 升级中得以提高的 “见证数据体积限制(witness size limit)”。

这两个决定,都在生态中的一小群非常活跃的资深用户那里引发了争议。我不会讨论区块体积的增加,这是加入区块重量限制的一部分,是那时候向持有不同意见的用户的妥协(他们正在推动一次提高区块体积限制的硬分叉),而且那时候也被网络的参与者们认为是安全的;但是见证数据折扣(witness discount)这个机制是重要的。

比特币交易手续费的横向比较基于一笔交易所包含的数据量,而与这笔交易转移的价值多少无关,它完全是由输入、输出(以及见证)的数量以及它们的体积(以字节计)决定的。前面我已经提到,在隔离见证升级以前,脚本签名(或者说签名和其它数据)是包含在交易的输出中的。这是一大块的数据,在输入中有,在输出中没有。

这就意味着,从一笔交易的角度看,输入比输出更贵,而且贵上不少。这就产生了一种长期的激励因素,让用户也倾向于花费面额较大的输出、创造出找零输出,而不是花费大量积累起来的小面额输出。也就是说,这是一种长期的经济激励,鼓励用户持续地让 UTXO 集膨胀 —— 而存储 UTXO 集是所有全节点验证交易和区块的前提。

见证数据折扣的出发点就纠正这种价格差异,缩小它而不是增大它。为了在经济上激励负责任的 UTXO 管理,这是极为重要的,至少在理论上,对于只想使用比特币协议的经济理性用户来说是如此。

Taproot 升级则移除了对一笔交易的见证字段的数据体积限制。在隔离见证升级后,这个限制是 10,000 字节。这样做是因为,Taproot 的设计已经缓解了构造出难以验证的交易的可能性,而在 tapscript 中尝试加入这样的体积限制,会给 “Miniscript” 带来大量的复杂性。这个限制所要防止的问题并不影响 Taproot ,而它又会给一个意图让定制化脚本更加安全、更平易近人的工具增加复杂性(所以开发者们决定移除它)。

(译者注:Miniscript 是一种编程语言,可以结构化地组合比特币脚本的片段,从而让整个锁定脚本更容易分析,也更安全。)

全景

这两项变更,都为拓展比特币、让更多人能以自主保管方式使用比特币,搬开了巨大的路障;但为了做到这一点,它们必然要大量变更协议的基础部分。

我希望以往不熟悉这些设计抉择以及背后哲学的读者,可以理解这些关切,并进一步思考它们的设计方式。比特币是一个动人心魄的创造,这毫无疑问,但它无法将好处播撒到可观比例的人群。

隔离见证和 Taproot 奠定了两个基石,为了解决比特币的可扩展性短板,它们是绝对必要的。如果没有这两项提议(或者解决相同的问题的替代性协议变更),我们今天拥有的所有这些成长中的可扩展性协议和系统都只是梦幻泡影。

Ark、Spark、BitVM、DLC —— 没有任何一个有可能出现。

这就是全景。今天的比特币也不是完美的,但它开始有很好的机会扩展到足够多的人群、对世界产生真实的影响、为尝试离场的人提供真正的替代方案。这都是因为这两项协议升级:它们消除了那些根本的障碍。

(完)

脚注

1. https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki

2. https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki

3. https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki

4. https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki

5. https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki

6. https://github.com/siv2r/bip-frost-signing

7. https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki

8. https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki