BIP-0118:bip-anyprevout 上的 Taproot 脚本公钥类型

  • ajtowns
  • 发布于 2025-04-11 11:33
  • 阅读 19

该BIP(Bitcoin Improvement Proposal)提议引入一种新的Taproot脚本公钥类型(SIGHASH_ANYPREVOUT),允许签名不绑定到特定的UTXO,从而使交易可以动态地绑定到具有兼容脚本的不同UTXO。这通过修改签名创建和验证中使用的交易摘要算法来实现,排除对先前输出的承诺,从而实现更灵活的链下协议和交易反应。

跳到内容

ajtowns/ bips Public

forked from bitcoin/bips

折叠文件树

文件

bip-anyprevout

搜索此仓库

/

bip-0118.mediawiki

复制路径

BlameMore file actions

BlameMore file actions

最近提交

ajtownsajtowns

BIP118: tweak wording around 1-byte pubkey

Jul 2, 2021

d616d54 · Jul 2, 2021

历史

历史

打开提交详情

查看此文件的提交历史。

213 行 (151 loc) · 21.2 KB

/

bip-0118.mediawiki

顶部

文件元数据和控件

  • 预览

  • 代码

  • Blame

213 行 (151 loc) · 21.2 KB

Raw

复制原始文件

下载原始文件

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

Introduction

Permalink: Introduction

Abstract

Permalink: Abstract

此 BIP 描述了 tapscript(BIP 342)交易的一种新型公钥。 它允许这些公钥的签名不提交到正在花费的确切 UTXO。 这使得交易可以动态绑定到不同的 UTXO,只要它们具有兼容的脚本。

Copyright

Permalink: Copyright

本文档根据 3-clause BSD 许可证获得许可。

Motivation

Permalink: Motivation

链下协议使用尚未广播到比特币网络的交易,以便重新协商应该在链上结算的最终状态。 在许多情况下,希望以另一种交易的形式,用预定的反应来响应在链上看到的给定交易。 通常,对于可能在链上看到的各种不同交易,都希望有相同的反应,但是由于响应交易中的输入签名会提交到正在反应的确切交易,这意味着必须为你希望能够响应的每笔可能的交易创建一个新的签名。

该提案引入了一种新的公钥类型[ 1],它通过排除对先前输出(以及,可选地,见证脚本[ 2]和值[ 3])的承诺,来修改签名创建和验证中使用的交易摘要算法的行为。 删除此承诺允许将已签名的交易动态地重新绑定到另一个需要相同密钥授权的先前输出。

由于使用了单独的公钥类型,因此动态重新绑定是选择加入,并且签名可以重新绑定的交易范围可以通过使用不同的密钥,将签名中的脚本提交,使用 UTXO 之间不同的金额,在消费交易中使用不同的 nSequence 值,或使用 codeseparator 操作码提交到脚本中的位置来进一步限制。

Specification

Permalink: Specification

此 BIP 修改了BIP 342签名操作码[ 4](CHECKSIGCHECKSIGVERIFYCHECKSIGADD) 的行为,这些公钥的长度为 33 字节,第一个字节为 0x01 或精确到单字节向量 0x01 的公钥[ 5]。 这些密钥被称为 BIP 118 公钥

Rules for signature opcodes

Permalink: Rules for signature opcodes

BIP 342签名操作码的规则被修改,方法是从未知公钥类型列表中删除第一个字节为 0x01 且长度为 1 字节或 33 字节的密钥,并在处理未知公钥类型之前添加以下规则:

  • 如果公钥是单字节 0x01,或者如果公钥是 33 字节并且公钥的第一个字节是 0x01,则它被认为是 BIP 118 公钥:
    • 如果签名不是空向量,则根据BIP 341签名验证规则,使用公钥、允许的 hash_type 值和如下定义的修改后的事务摘要来验证签名。
Public key

Permalink: Public key

要转换 1 字节的 BIP 118 公钥以与BIP 340一起使用,请使用BIP 341中定义的 32 字节 taproot internal key,p

要转换 33 字节的 BIP 118 公钥以与BIP 340一起使用,请删除 0x01 前缀并使用剩余的 32 字节。

Signature message

Permalink: Signature message

函数 SigMsg118(hash_type, ext_flag) 计算被签名的消息作为字节数组,类似于BIP 341 中定义的 SigMsg(hash_type, ext_flag)SigExt118(hash_type,key_version) 计算扩展,类似于BIP 342

参数 hash_type 是一个 8 位无符号值,重用BIP 341中定义的值,此外,值 0x410x420x430xc10xc20xc3 也对 BIP 118 公钥有效。

我们使用 hash_type 的位 6 和 7 定义以下常量:

  • SIGHASH_ANYPREVOUT = 0x40
  • SIGHASH_ANYPREVOUTANYSCRIPT = 0xc0

按照BIP 341的规定,参数 ext_flag 是 0-127 范围内的整数,用于指示扩展已添加到消息的末尾。参数 key_version 是一个 8 位无符号值(0-255 范围内的整数),用于提交到公钥版本。

以下限制适用,如果违反会导致验证失败:

  • 使用任何未定义的 hash_type (不是 0x000x010x020x030x410x420x430x810x820x830xc10xc20xc3)。
  • 在没有“相应的输出”(索引与正在验证的输入相同的输出)的情况下使用 SIGHASH_SINGLE

如果未违反这些限制,则 SigMsg118(hash_type,ext_flag) 的计算结果为以下数据的串联,按顺序(每个项目的大小以字节列出)。2、4 或 8 字节项目中的数值以小端字节序编码。

  • 控制:
    • hash_type (1)。
  • 交易数据:
    • nVersion (4):交易的 nVersion
    • nLockTime (4):交易的 nLockTime
    • 如果 hash_type & 0xc0 为零:
    • sha_prevouts (32):所有输入 outpoint 的序列化的 SHA256。
    • sha_amounts (32):所有已花费的输出金额的序列化的 SHA256。
    • sha_scriptpubkeys (32):所有已花费的输出 scriptPubKey 的序列化的 SHA256。
    • sha_sequences (32):所有输入 nSequence 的序列化的 SHA256。
    • 如果 hash_type & 3 不等于 SIGHASH_NONESIGHASH_SINGLE
    • sha_outputs (32):CTxOut 格式的所有输出的序列化的 SHA256。
  • 有关此输入的数据:
    • spend_type (1):等于 (ext_flag * 2) + annex_present,其中 annex_present 是 0(如果不存在 annex),否则为 1(原始见证堆栈有两个或多个见证元素,并且最后一个元素的第一个字节是 0x50
    • 如果 hash_type & 0xc0 不为零:
    • 如果 hash_type & 0xc0SIGHASH_ANYONECANPAY
      • outpoint (36):此输入的 COutPoint(32 字节哈希 + 4 字节小端)。
    • 如果 hash_type & 0xc0SIGHASH_ANYONECANPAYSIGHASH_ANYPREVOUT
      • amount (8):此输入花费的先前输出的值。
      • scriptPubKey (35):此输入花费的先前输出的 scriptPubKey,序列化为 CTxOut 内的脚本。它的大小始终为 35 字节。
    • nSequence (4):此输入的 nSequence
    • 如果 hash_type & 0xc0 为零:
    • input_index (4):此输入在事务输入向量中的索引。第一个输入的索引为 0。
    • 如果存在 annex(设置了 spend_type 的最低位):
    • sha_annex (32):(compact_size(annex 大小) || annex) 的 SHA256,其中 annex 包括强制性的 0x50 前缀。
  • 有关此输出的数据:
    • 如果 hash_type & 3 等于 SIGHASH_SINGLE
    • sha_single_output (32):CTxOut 格式的相应输出的 SHA256。

类似地,SigExt118(hash_type,key_version) 的计算结果为以下各项的串联:

  • 扩展:
    • 如果 hash_type & 0xc0 不是 SIGHASH_ANYPREVOUTANYSCRIPT
    • tapleaf_hash (32):BIP 341 中定义的 tapleaf 哈希
    • key_version (1)。
    • codesep_pos (4):在当前执行的签名操作码之前最后执行的 OP_CODESEPARATOR 的操作码位置,值采用小端格式(如果没有执行,则为 0xffffffff)。脚本中的第一个操作码的位置为 0。无论被推送的数据的大小如何,多字节推送操作码都算作一个操作码。

请注意,如果 hash_type & 0x40 为零,则 SigMsg118(hash_type,ext_flag) == SigMsg(hash_type,ext_flag),并且 SigExt118(hash_type,0x00) == ext(其中 extBIP 342中定义的消息扩展)。

要验证 BIP 118 公钥 p 的签名 sig

  • 如果 sig 的长度为 64 字节,则返回 Verify(p, hashTapSigHash(0x00 || SigMsg118(0x00, 1) || SigExt118(0x00, 0x02), sig), 其中 VerifyBIP 340中定义。
  • 如果 sig 的长度为 65 字节,则返回 sig[64] ≠ 0x00 and Verify(p, hashTapSighash(0x00 || SigMsg118(sig[64], 1) || SigExt118(sig[64], 0x02), sig[0:64]).
  • 否则,失败。

BIP 342签名验证的主要区别在于:

  • 在所有情况下,key_version 都设置为常量值 0x01 而不是 0x00。[ 6]
  • 如果设置了 SIGHASH_ANYPREVOUT,则计算摘要,就好像设置了 SIGHASH_ANYONECANPAY,除了 outpoint 不包含在摘要中。
  • 如果设置了 SIGHASH_ANYPREVOUTANYSCRIPT,则计算摘要,就好像设置了 SIGHASH_ANYONECANPAY,除了 outpointscriptPubKeytapleaf_hash 不包含在摘要中。

Security

Permalink: Security

Signature replay

Permalink: Signature replay

根据设计,与 SIGHASH_ALLSIGHASH_ANYONECANPAY 签名相比,SIGHASH_ANYPREVOUTSIGHASH_ANYPREVOUTANYSCRIPT 引入了额外的签名重放可能性(即它们允许在不同的交易中重复使用相同的签名)。

SIGHASH_ALLSIGHASH_ANYONECANPAY 签名都通过提交到一个或多个输入来防止签名重放,因此只有在同一个输入可以多次花费的情况下才可能重放签名,这在比特币区块链上是不可能的(由于强制执行 BIP 30)。 使用 SIGHASH_ANYPREVOUT 签名,对于具有相同 scriptPubKey 和相同值的不同 UTXO,签名重放是可能的,而使用 SIGHASH_ANYPREVOUTANYSCRIPT,对于在其潜在脚本之一中重复使用相同 BIP 118 公钥的任何 UTXO,签名重放是可能的。

因此,实施者必须确保仅在签名重放不会导致资金损失时(例如,由于协议的其他功能或交易的其他约束),或者当这种资金损失是可以接受的时,才重复使用 BIP 118 公钥。

Malleability

Permalink: Malleability

使用 SIGHASH_ANYPREVOUTSIGHASH_ANYPREVOUTANYSCRIPT 可能会引入额外的可延展性向量。

特别是,仅使用 ANYPREVOUT 签名进行身份验证的交易对于任何能够提供由签名满足的替代输入的人来说都是可延展的——以这种方式更改的输入将产生一个新的有效交易,支付给相同的接收者,但具有不同的 txid。 根据输入的更改,这可能会与原始交易冲突(如果某些输入仍然共享),或者可能会导致对接收者的双重支付(如果他们不这样做)。

此外,对于使用相同的 scriptPubKey 和值的一系列交易,并且仅通过 ANYPREVOUT 签名进行身份验证(如 eltoo 为失败案例所设想的那样),任何第三方都可能延展交易(及其 txid),而无需访问任何私钥,特别是通过省略中间交易。

这种形式的延展可以通过子交易也使用 ANYPREVOUT 签名来解决——当父交易被延展时,可以调整其子交易以引用新的 txid 作为输入,并且 ANYPREVOUT 签名仍然有效。

但是,如果子交易的输入以这种方式被延展,则由 SIGHASH_ALLSIGHASH_ANYONECANPAY 签名授权的子交易将需要新的签名。 可以通过在使用 ANYPREVOUT 签名通过 SIGHASH_ALLSIGHASH_ANYONECANPAY 授权的 UTXO 之前使用 BIP 68/BIP 112 相对时间锁来稍微减轻这种风险:相对时间锁可以确保输入具有足够的确认数,以至于它们只能在发生大型区块重组的情况下被替换。 请注意,此方法有缺点:相对时间锁会阻止通过子支付父级来提高费用,并且具有明显的缺点,即在时间锁到期之前,资金暂时无法使用。

Privacy considerations

Permalink: Privacy considerations

预计在实践中,ANYPREVOUT 签名将很少使用。 协议和钱包设计者应尽可能地使他们的交易使用 Taproot 密钥路径花费,这既是出于交易权重较低的效率原因,也是出于隐私原因,以避免第三方能够将他们的交易与其他协议的交易区分开来。

因此,确实使用 ANYPREVOUT 签名的交易将揭示有关该交易的信息,可能包括合作是不可能的,或者使用了什么协议或软件(由于脚本的详细信息)。

为了最大限度地提高隐私,因此建议协议设计者仅在将使用至少一个 ANYPREVOUT 签名花费的脚本中使用 BIP 118 公钥,并在 taproot merkle 树中使用密钥路径花费或备用脚本用于任何可以未经 ANYPREVOUT 签名授权的花费。 遵循此建议可能需要额外的脚本分支,这可能意味着在某些情况下,无视此建议可能会导致成本和隐私之间更好的权衡。

Rationale

Permalink: Rationale

  1. ^ 为什么是新的公钥类型? 可以通过指定BIP 342中指定的_未知公钥类型_的新规则,在软分叉中引入用于 tapscript 的新公钥类型,因为这只需要对预先存在的签名操作码添加限制。 可能的替代方法是定义新的脚本操作码,使用不同的 taproot 叶版本,或使用与BIP 341指定的不同的 SegWit 输出集;但是,所有这些方法都更加复杂,最好为其他需要实际额外灵活性的升级保留。 在这种情况下,我们指定一个新的交易摘要,但保留相同的椭圆曲线和签名算法(即,secp256k1 和BIP 340)。

  2. ^ 为什么(以及为什么不)提交到见证脚本? eltoo 论文提供了一个示例,说明为什么提交到见证脚本并不总是合适的。 它使用脚本和交易 nLockTime 使签名不对称,以便具有较早签名的交易可以由具有较晚签名的交易花费,但具有较晚签名的交易不能由具有较早签名的交易花费。 因此,第三个甚至更晚的交易的单个签名必须能够花费先前的两个交易,即使它们具有不同的 tapscript。 另一方面,这些情况也提供了充分的理由来选择提交到脚本:因为每个交易都有一个新的脚本,提交到脚本允许你生成一个精确应用于其中一个交易的签名。 在 eltoo 情况下,这允许你拥有一个更新交易的签名,该签名可以应用于任何先前的更新,以及一个仅应用于相应更新交易的结算交易的签名,同时对两者使用相同的密钥,这反过来允许更紧凑的脚本。

  3. ^ 为什么(以及为什么不)提交到输入值? 提交到输入值可能会提供额外的安全性,即签名不能被恶意重用来声明签名者不打算花费的资金,因此默认情况下,提交到输入值似乎是明智的。但是,这样做会阻止能够使用单个签名将一组具有相同花费条件的 UTXO 合并到单个 UTXO 中,这对于某些协议可能很有用,例如使用 eltoo 的分层承诺的提案

  4. ^ 密钥路径花费呢? 本提案仅支持通过脚本路径花费的 ANYPREVOUT 签名,不支持密钥路径花费的 ANYPREVOUT 签名。 这是出于两个原因:首先,不支持密钥路径花费允许本提案独立于BIP 341BIP 342中包含的核心更改;其次,它允许地址选择加入或退出 ANYPREVOUT 支持,同时在花费之前保持无法区分。

  5. ^ 使用 0x01 公钥类型 因为 OP_0 在堆栈上留下一个空向量,所以它不满足BIP 342的未知公钥类型的规则。因此,使用 OP_1..OP_16OP_1NEGATE 之一作为引用 taproot 内部密钥的方式很方便。 为了尽可能简单,我们使用第一个,并添加相同的字节作为前缀,以允许显式指定密钥的 ANYPREVOUT 签名。

  6. ^ 为什么要更改 key_version? 更改 key_version 确保如果使用相同的私钥生成 BIP 342 密钥和 BIP 118 公钥,则 BIP 342 密钥的签名对于 BIP 118 公钥(反之亦然)也无效。

Deployment

Permalink: Deployment

TODO

可以与BIP 340BIP 341BIP 342的部署同时或之后,将其部署为软分叉。

Backwards compatibility

Permalink: Backwards compatibility 作为一个软分叉,旧的软件将继续运行而无需修改。 没有升级以支持 BIP 341 的节点会将所有 taproot witness programs 视为 anyone-can-spend 脚本,而升级以支持 BIP 341BIP 342 但不支持 BIP 118 的节点,会将任何针对 BIP 118 公钥的非空签名视为有效。 因此,强烈建议节点进行升级,以便完全验证新公钥类型的签名。

未升级的钱包可以使用 SegWit version 0 programs、传统的 pay-to-pubkey-hash 等,从非升级和升级的钱包接收和发送比特币。 根据实现的不同,如果未升级的钱包支持发送到 BIP350 Bech32m 地址,并且不会因为认为输出不标准而阻止交易广播,则可能能够发送到 SegWit version 1 programs。

修订

Permalink: Revisions

除了基于 Taproot 而不是 SegWit v0 之外,此 BIP 的主要区别在于:

  • sighash 标志已从 “NOINPUT” 重命名为 “ANYPREVOUT”,以反映虽然任何 prevout 都可以与签名一起使用,但 input 的某些方面仍然会被提交,即 input 的 nSequence 值,以及(可选)花费条件和金额。
  • 以前,NOINPUT 适用于直接公钥花费(假设部署以类似于 BIP 141 P2WPKH 和 P2WSH 的方式进行扩展),但此提案仅适用于通过 tapscript 的签名,而不适用于直接密钥路径花费。这意味着地址必须选择通过在创建地址时包含适当的 tapscript 路径,才能被 SIGHASH_ANYPREVOUTSIGHASH_ANYPREVOUTANYSCRIPT 签名花费。
  • NOINPUT 签名不通过 scriptPubKey 或 redeem/witness script 提交到 output 的花费条件。当使用 SIGHASH_ANYPREVOUTANYSCRIPT 时,此行为得以保留,但当使用 SIGHASH_ANYPREVOUT 时,签名现在会提交到 scriptPubKey 和 tapscript。
  • NOINPUT 签名确实提交到 input 的金额。当使用 SIGHASH_ANYPREVOUT 时,此行为得以保留,但当使用 SIGHASH_ANYPREVOUTANYSCRIPT 时则不然。
  • 脚本中的 OP_CODESEPARATOR 将影响 SIGHASH_ANYPREVOUTSIGHASH_ANYPREVOUTANYSCRIPT 签名,而在之前的草案中则不会。

致谢

Permalink: Acknowledgements

SIGHASH_NOINPUT 标志最初由 Joseph Poon 在 2016 年 2 月 提出,此前 Joseph Poon 和 Thaddeus Dryja 在最初的 Lightning paper 中提到了它。 本文档是与许多人讨论的结果,并得到了 Greg Maxwell、Jonas Nick、Pieter Wuille 等人的直接投入。

  • 原文链接: github.com/ajtowns/bips/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ajtowns
ajtowns
江湖只有他的大名,没有他的介绍。