Roasbeef/bips 中的 bips/bip-tap.mediawiki,提交哈希值为 bd3cdc153beaa901f26ef6504ea89e8f5e00b921

  • Roasbeef
  • 发布于 2025-11-01 12:26
  • 阅读 14

该文档描述了TAP,一个构建在比特币区块链之上的Taproot原生资产协议。

跳到内容

你用另一个标签页或窗口登录了。重新加载 以刷新你的会话。你在另一个标签页或窗口中退出了。重新加载 以刷新你的会话。你在另一个标签页或窗口中切换了帐户。重新加载 以刷新你的会话。忽略警报

{{ message }}

Roasbeef/ bips 公开

fork 自 bitcoin/bips

折叠文件树

文件

文件在默认分支上不存在

bd3cdc1

搜索此存储库

/

bip-tap.mediawiki

复制路径

Blame 更多文件操作

Blame 更多文件操作

最近的提交

历史

历史

查看此文件的提交历史。

1111 行 (892 行代码) · 62.9 KB

/

bip-tap.mediawiki

顶部

文件元数据和控件

  • 预览

  • 代码

  • Blame

1111 行 (892 行代码) · 62.9 KB

Raw

复制原始文件

下载原始文件

大纲

编辑和原始操作

 BIP: ???
  Layer: Applications
  Title: TAP: Taproot Assets Protocol
  Author: Olaoluwa Osuntokun <laolu32@gmail.com>
  Comments-Summary: No comments yet.
  Comments-URI: https://git
  Status: Draft
  Type: Standards Track
  Created: 2021-12-10
  License: BSD-2-Clause
## 目录<br>永久链接: 目录<br>- 摘要<br>- 版权<br>- 动机<br>- 设计 <br> - Merkle-Sum Sparse Merkle Trees<br> - Taproot Asset Trees<br> - Asset Provenance<br> - Merkle-Sum based Proof of Reserves<br> - Splits, Merges, collectibles and Normal Divisible Assets<br> - 规范 <br> - Asset Tree Representation <br> - Asset Root Commitment<br> - Asset Leaf Format<br> - Asset Creation<br> - Asset Burning<br> - Asset Transfers <br> - Asset Swap Transactions <br> - Collectible Asset Transfers<br> - Normal Asset Transfers<br> - Normal Asset Transfers<br> - Taproot Asset Files & Leaf Verification<br> - Asset Universes<br> - Multi-Hop Taproot Asset Transfer<br>- 应用<br>- 测试向量<br>- 向后兼容性<br>- 致谢<br>- 参考实现

摘要

永久链接: 摘要

本文档描述了 TAP,这是一种构建在基础比特币区块链之上的 Taproot 原生资产叠加层。Taproot 资产能够在比特币之上表示任意(普通和收藏品)资产,而不会使基础链膨胀。该协议的设计使得与 Taproot 资产交互的交易与比特币区块链 PoV 中的常规交易无法区分。Taproot 资产使用嵌套的 资产脚本 树(一种 Merkle-Sum Sparse Merkle Tree,或 MS-SMT)扩展了基础 Taproot 脚本树,该树将有效的 witness 作为结构化元数据进行提交,从而可以证明资产在交易图中的移动。可以使用作为扁平文件传输的密封证明来验证 Taproot 资产转移的来源,或者借助外部维护的 Universe,这是一个 MS-SMT,用于索引链上资产的发行和转移,从而原生支持储备证明/供应系统。

Taproot 资产支持通过闪电通道(基于 BOLT 协议套件)进行链下单跳和多跳转移,后者通过 Taproot 资产独特的嵌入式资产脚本系统来实现。一系列链上和链下的 merkle 证明有助于对链上 Taproot 资产转移进行轻客户端验证,这些证明可以通过将信任关系委托给活动的 Universe 实例来压缩。提出了一种链下多方通道的变体,以支持普通资产的链下转移。此外,一种特殊类型的 Universe,称为 Pocket Universe,它基于仅退出的提交链设计,可用于以最小化信任的方式在链上聚合转移。

版权

永久链接: 版权

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

动机

永久链接: 动机

作为第一个去中心化区块链的比特币,在其发展的早期就实现了几个系统,试图在比特币系统本身的约束范围内表示任意资产。在这些系统中最早的是 Mastercoin(现在称为 OMNI)和 Counterparty,它们是构建在比特币之上的元Token协议,使用 OP_RETURN 来提交系统中资产的原始表示形式和转移。在 OMNI 和其他相关系统创建和部署几年后,这些系统内的活动很少,而是分散到数十个新的区块链,这些区块链没有直接追溯到比特币,即启动所有区块链的链。

Taproot Assets 的目标是接过火炬,并实现一个在比特币上表示和操作任意资产的系统,该系统反映了现代区块链的设计原则,并提供了一个受 Taproot 启发的,比特币开发者会感到熟悉的数据结构和协议流程。重要的是,这样一个系统必须从头开始设计,以便在链下环境中工作,以确保基础链不会因不可扩展的叠加协议而膨胀。通过明确的规范,我们的目标是鼓励该系统被广泛的生态系统采用,从而激发现有分配不足的开发者热情和资源。

通过允许比特币开发者以私密、可扩展的方式轻松表达和操作任意资产,我们的目标是提高比特币系统的效用,从而产生对区块空间的额外需求,这对于确保系统能够在区块补贴逐渐减少到零的环境中蓬勃发展是必要的。

设计

永久链接: 设计

在本节中,我们将提供 Taproot Assets 协议组成的基本数据结构和概念的概要。Taproot Assets 从在 taproot 脚本树中提交任意非脚本数据的简单想法开始,然后在此想法的基础上创建一个建立在比特币链中的任意资产的叠加协议。

Merkle-Sum Sparse Merkle Trees

永久链接: Merkle-Sum Sparse Merkle Trees

merkle 树是经过身份验证的数据结构,基于元素的 列表。它允许我们执行诸如获取目录的内容并创建一个根哈希之类的操作,该根哈希允许我们证明给定的文件属于有问题的目录。每个元素都成对进行哈希处理,从底部开始,直到只剩下一个哈希为止。我们将此哈希称为根哈希。

merkle-sum 树是 merkle 树的一种变体,我们的哈希运算还提交了给定属性的 总和。我们可以通过提交每个文件的大小来扩展上面的示例。然后,根哈希提交到左子树,右子树以及左右子树的大小之和。这种新的变体很有用,因为我们可以证明文件的存在及其大小。我们还可以执行诸如生成子目录大小证明之类的操作。

我们使用 merkle-sum 树无法轻松地做的一件事是证明不存在,因为如果项目未按规范排序,则证明不存在需要显示树中的所有叶子。如果我们选择对 merkle 树中的叶子集进行排序,那么我们将能够更容易地证明不存在,但是我们会引入每次插入新项目时都需要重新平衡树的开销。在 Taproot Asset 设置中,证明不存在很有用,因为我们可能希望资产的卖方证明他们不再承诺有问题的资产。

Sparse Merkle Tree 是一个基于一系列键值对的 merkle 树“模拟”,它支持高效的非包含证明。SMT 实际上由整个键空间组成(所有 256 位值),也就是说,它是一棵具有 2^256 个叶子的树(因此具有 256 个级别)。该结构的表示之所以易于处理,是因为我们知道空元素的哈希值、具有两个空子树的分支的哈希值等等。此外,一系列缓存策略可用于使表示更加高效。通过添加一个位图,如果证明中的中间分支提交到空子树,则该位图会发出信号,从而可以进一步压缩证明。

Merkle-Sum Sparse Merkle Tree 是一个 SMT,它也继承了 sum-combiner 特征。我们使用此数据结构来允许轻松验证可分割资产的拆分、支持非包含证明,并用作 merkalized 查找表,以帮助验证 Taproot Asset 证明。

本文档中提到的 MS-SMT 在 BIP bip-tap-smt 中有完整说明。

Taproot Asset Trees

永久链接: Taproot Asset Trees

Taproot Assets 协议是一种 Taproot 原生资产叠加层,可用于使用基础比特币区块链创建和转移收藏品或普通资产。资产表示为 现有 Taproot 脚本树中对结构化数据的提交。此结构化数据永远不会以纯文本形式写入基础链本身,而是由 Taproot Assets 叠加协议在更高的层上维护。资产本身由主资产树中的一系列 MS-SMT(每个资产 ID/类型一个)表示。每个资产(除了许多其他属性外)还会提交到 资产脚本哈希,该哈希提交到 资产脚本,该脚本从 Taproot Assets 叠加协议的 PoV 限制了资产可能被转移的 方式。该系统的初始版本使用比特币脚本的子集,以允许资产表达关于资产有效转移的任意条件。

因此,Taproot Asset 叶子反映了基础比特币区块链上 UTXO 的编程性。给定 Taproot Asset 的验证者将拒绝任何无效的状态转换。因此,我们继承了与基础脚本系统相当(并且通过新的资产脚本版本也超越)的编程级别,这是促进通过闪电网络进行多跳链下转移(通过 嵌入 在资产脚本中的 HTLC)的关键要求。

Asset Provenance

永久链接: Asset Provenance

资产的来源使用两种机制之一来证明。第一个机制,在下文中称为“完整证明”,是一个结构化文件,其中包含来自初始 創世输出 的序列化证明,该证明具有 一系列有效的资产 witness,这些 witness 可验证地将资产的所有权转移到 taproot 输出上。完整证明通常表示为平面文件,供 Taproot Assets 协议消费、验证和显示。

第二种证明/验证来源的方法是一种结构略有不同的 MS-SMT,它也在 Taproot 脚本树中提交。我们将此元结构称为 Universe,因为它在链中提交 Taproot Asset 承诺 以及其他证明数据。Universe 是一个键值存储,可用于引导来源验证(由创建感兴趣的资产集的人员维护)。除了初始創世输出验证之外,Universe 还可以通过在 MS-SMT 中记录所有有效的 Taproot Asset 转移来充当可扩展性层,该 MS-SMT 将 资产identifier 映射到资产的最后一个已知有效转移。

Merkle-Sum based Proof of Reserves

永久链接: Merkle-Sum based Proof of Reserves

MS-SMT 数据结构的使用使系统能够支持高效的供应/非通货膨胀证明,从而使参与者可以轻松验证在给定 taproot 输出中承诺的资产总额,以及给定 Universe 发行的资产总集。SMT 的 merkle-sum 扩展允许资产可分割,同时允许验证者声明,与常规比特币交易类似,在资产創世交易之外的转移过程中不会创建新资产。

Splits, Merges, collectibles and Normal Divisible Assets

永久链接: Splits, Merges, collectibles and Normal Divisible Assets

Taproot Assets 能够表示收藏品和普通可分割资产。普通资产提交持有资产的总价值,这些资产可以在 内部 树中(类似于普通比特币 UTXO)以及跨顶级 Taproot 输出进行拆分。 我们将这些称为内部和外部拆分。普通资产也可以合并,其过程与基础层上的 UTXO 合并类似。在转移资产期间,资产的持有者证明他们持有有效的拆分(通过 merkle-sum 证明),每个创建的资产都提交到新的 merkle-sum 输出拆分集,以在转移期间强制执行非通货膨胀。

另一方面,收藏品无法拆分或合并。它们通常以批次创建,并且通常表示对链级别或现实世界资产/功能的声明/凭证(假设存在信任关系)。集合的一个示例是一系列限量版数字收藏品,例如棒球卡或集换式卡片游戏。

普通资产可以使用闪电网络以多跳方式在链下转移,而收藏品资产必须在链上转移或提升到多方通道中,以允许在已知的一组参与者之间进行转移。

Specification

永久链接: Specification

Asset Tree Representation

永久链接: Asset Tree Representation

Asset Root Commitment

永久链接: Asset Root Commitment

Taproot Asset 树是系统的核心组件。资产树是一个 MS-SMT,用于提交一系列资产identifier,这些资产按其創世资产 ID 分组。给定 Taproot Asset 树由两个嵌套的 MS-SMT 实例组成:

  1. 第一层将 asset_idasset_group_key 映射到给定资产的子树根哈希。
  2. 第二层将 asset_script_keyasset_id || asset_script_key 映射到序列化的 Taproot Asset 叶子。

观察 BIP-341,资产树的根哈希表示为一个 Tapscript 树,该树提交给一个唯一的叶子:

  • tagged_hash("TapLeaf", leaf_version || taproot_asset_marker || taproot_asset_version || asset_tree_root)

其中:

  • taproot_asset_marker 是 ascii 字符串 "taproot-assets" 的 sha256 哈希值。
  • taproot_asset_version 是 Taproot Assets 系统的版本,该版本定义了如何解释承诺值的其余部分。
  • asset_tree_root 是一个 40 字节(哈希为 32 字节,值为 8 字节)的 MS-SMT 根。

选择 ??? 的 leaf_version。从比特币系统的 PoV 来看,我们只是提交了一个带有无法解析的脚本的 tapscript 叶子。将来,如果比特币系统被软分叉以了解 Taproot Asset 特定的承诺,那么可以使用相同或不同的叶子版本来控制新行为的验证。

asset_id 是以下内容的 32 字节哈希:

  • sha256(genesis_outpoint || sha256(asset_tag) || asset_meta_hash || output_index || asset_type)

其中:

  • genesis_outpoint 是资产編ジェネシス交易中使用的第一个前一个输入 outpoint,以比特币 wire 格式序列化。
  • asset_tag 是一个随机的 32 字节值,表示给定的资产,可用于将一系列离散资产链接到单个资产组中。在实践中,这通常将是人类可读的资产名称的哈希。
  • asset_meta_hash 是一个不透明的 32 字节值,可用于提交各种元数据,包括外部链接、文档、统计、属性、图像等。重要的是,此字段被认为是不可变的
    • 創世资产证明必须包含 asset_meta_hash 的原像,这允许验证者获取提交的数据并验证 sha2 原像。
  • output_index(4 字节,大端)是創世交易中包含唯一 Taproot Asset 承诺的输出的索引。
  • asset_type(1 字节)是要铸造的资产的类型。

鉴于上述结构,从链的 PoV 来看,asset_id 保证是全局唯一的,因为感谢 BIP 34 因为 outpoint 永远不会在区块链中序列化后重复。

此外,我们强制规定给定的输出必须仅具有 单个 根 Taproot Asset 承诺。为了验证此属性,我们对根 Taproot Asset 树承诺的位置强制执行以下约束:

  • 资产根承诺必须是 tapscript 树中最左侧或最右侧的叶子:
    • 我们通过要求在脚本树中显示的 Taproot Asset 承诺的深度为 0 或 1 来强制执行此操作。
  • 对于深度为 0 的显示证明(32 字节的控制块),Taproot Asset 承诺是控制块证明中唯一的元素,因为它直接成为根哈希。
  • 对于深度为 1 的显示证明(64 字节的控制块),我们要求证明者还显示同级哈希的原像。
    • 在深度为 1 的根位置,Taproot Asset 承诺是完全排序的 tapscript 树中最左侧或最右侧的元素。
    • 要成为有效的 Taproot Asset 根承诺,同级哈希原像必须:
    • 恰好是 64 字节,这意味着同级本身是一个 tap 分支(Taproot Asset 根原像本身是 76 字节:2 字节版本,32 字节 Taproot Asset 标记,2 字节 Taproot Asset 版本,32 字节哈希,8 字节总和值),因为它受其 BIP-340 标记哈希标签的约束。
    • 或者,是一个 tap 叶子,可以通过唯一的 BIP-340 标记哈希标签进行验证。
      • 在这种情况下,必须根据原始消息摘要验证叶子,以检测并拒绝 tapscript 树中重复的 Taproot Asset 承诺包含(参见 taproot_asset_marker)。

由于在哈希之前对 tap 分支/叶子进行词典排序,因此我们失去了 merkle 树中的排序信息。因此,我们反而被迫要求显示同级原像。

以下算法可用于断言 tapscript 树中 Taproot Asset 承诺的唯一性:

taproot_asset_commitment_is_valid(commitment_output: TxOut, control_block: ControlBlock,
    sibling_preimage: TaprootAssetTapReveal, taproot_asset_root: []byte) -> bool

    taproot_asset_root_hash = tagged_hash("TapLeaf", taproot_asset_root)
    internal_key = parse_key(control_block.internal_key_bytes)

    match len(control_block.size):
       # Just the internal public key, so we can just verify the commitment below.
       # 只是内部公钥,因此我们可以只验证下面的承诺。
       case 32:
           expected_output_key = internal_key +
               tagged_hash("TapTweak", internal_key || taproot_asset_root_hash)*G

           return expected_output_key == witness_program(commitment_output.pk_script)

       # More than one element in the tree, so need to verify each sub-case.
       # 树中有多个元素,因此需要验证每个子案例。
       case 65:

           match sibling_preimage:
               # The pre-image is a non Taproot Asset leaf, so verify the hashes
               # match up.
               # 该原像是非 Taproot Asset 叶子,因此请验证哈希是否匹配。
               case LeafReveal(leaf_bytes):
                   # The leaf can't share the Taproot Asset marker bytes,
                   # otherwise it may be a legitimate commitment.
                   # 叶子不能共享 Taproot Asset 标记字节,否则它可能是一个合法的承诺。
                   if leaf_bytes[2:].starts_with(taproot_asset_marker):
                       return false

                   leaf_hash = tagged_hash("TapLeaf", leaf_bytes)

                   if leaf_hash != control_block.sibling_hash:
                       return false

               # The pre-image is itself a branch, so we need the two siblings
               # used to construct the branch.
               # 该原像本身是一个分支,因此我们需要用于构造该分支的两个同级。
               case BranchReveal(sibling_1, sibling_2):
                   expected_branch_hash = tagged_hash("TapBranch", sort(sibling_1, sibling_2))

                   if expected_branch_hash != construct.sibling_hash:
                       return false
```# 我们现在知道这棵树是结构良好的,所以我们将验证根的承诺。
           root_hash = tagged_hash("TapBranch", sort(taproot_asset_root_hash, control_block.sibling_hash))

           expected_output_key = internal_key + tagged_hash("TapTweak", internal_key || root_hash)*G

           return expected_output_key == witness_program(commitment_output.pk_script)

   default:
       return false

除了验证承诺在单个 taproot 树的约束内是唯一的之外,我们还需要验证在 genesis 交易的其余输出中没有其他**重复**或意外的承诺。我们可以通过断言以下内容来实现:

- 对于 genesis 交易中每个未创建资产的输出:
  - 如果顶层密钥是使用 BIP 86 派生的,则验证密钥派生。
  - 如果密钥提交到脚本路径:
    - 如果树中只有一个元素,则验证它不是重复的承诺。
    - 如果树包含多个元素,则验证两个分支的预图像不是重复的承诺。

在典型的 genesis 交易(1 个输入,1 个输出)的情况下,不需要交换额外的信息。但是,如果交易还有其他输出,则需要一个最小的控制块揭示(32 或 65 字节)。

以下算法可用于验证交易中其他位置的输出没有提交到重复的 Taproot Asset 承诺:

verify_no_taproot_asset_up_my_sleeves(genesis_tx: Tx, taproot_asset_root: []byte) -> bool

for tx_out in genesis_tx.tx_outs:
    # 我们可以忽略任何非 P2TR 输出,因为它们无法提交到 Taproot
    # Assets。
    if !commitment_expected(tx_out):
        continue

    # 我们预计此时会有一个承诺,所以我们将逐步完成
    # 我们的两个案例。
    match tx_out.taproot_commitment:
        # 单个叶子,所以我们只是验证它不是 Taproot Asset
        # 承诺。
        case SingleLeaf(leaf_bytes, internal_key):
           # 有人有一些‘说明’要做……
           if leaf_bytes == taproot_asset_root:
               return false

           leaf_hash = tagged_hash("TapLeaf", leaf_bytes)
           expected_output_key = internal_key + tagged_hash("TapTweak", internal_key || leaf_hash)*G

           if expected_output_key != witness_program(tx_out.pk_script):
               return false

       # 多个元素,所以我们验证两个预图像都不是
       # 是重复的承诺。
       case MultiLeaf(branch_1_bytes, branch_2_bytes):
           if branch_1_bytes == taproot_asset_root:
               return false

           if branch_2_bytes == taproot_asset_root:
               return false

           branch_hash = tagged_hash("TapBranch", sort(branch_1_bytes, branch_2_bytes))

           expected_output_key = internal_key + tagged_hash("TapTweak", internal_key || leaf_hash)*G

           if expected_output_key != witness_program(tx_out.pk_script):
               return false
return true

一个确定性的算法,用于构造一个最终的 taproot merkle 树哈希,给定一组单独的叶子,或者一个完整的 tapscript 树(根哈希),在 BIP [bip-tap-smt](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap-smt.mediawiki) 中进行了描述。

无法强制 `asset_tag` 字段是**全局**唯一的。相反,为了确保在初始资产创建时在本地唯一的 `asset_id` 实例,每个 `asset_tag` 和 `asset_meta_hash` 值在资产创建期间**必须**只出现一次。此外,`asset_meta_hash` 的**预图像**,被称为 `meta_reveal`,可以与初始 genesis 资产创建证明一起打包,以确保验证者可以获得给定资产的所有相关数据。

顶层 MS-SMT 提交到所有持有的已定义资产的集合。这个 MS-SMT 树的根哈希被称为 `asset_tree_root`。这个 MS-SMT 的结构如下:

- 键:`asset_id` 或 `asset_group_key`
- 值:`taproot_asset_version || asset_id_tree_root || asset_sum`
- sum_value: `asset_sum`

与 `asset_id` 类似,`asset_group_key` 的派生方式确保了系统内的唯一性,但可以在多个资产铸造之间共享。`asset_group_key` 的派生方式如下:

- `asset_group_key = TapTweak(asset_internal_group_key, asset_group_script_root)`

其中:

- `asset_raw_group_key` 是一个 32 字节的公钥,如 [BIP-340](https://github.com/Roasbeef/bips/blob/master/bip-0340.mediawiki) 中定义的那样。
- `asset_internal_group_key = SingleTweak(asset_raw_group_key, asset_id)`
- `asset_group_script_root` 是一个 taproot,可以容纳任意的资产脚本,强制执行资产铸造的条件。
  - `asset_raw_group_key` 和 `asset_group_script_root` 必须在资产 genesis 时揭示,以验证群组密钥,因此将随资产证明一起提供。

并且

- `TapTweak` 是 [BIP-341](https://github.com/Roasbeef/bips/blob/master/bip-0341.mediawiki) 中定义的 taproot 调整函数。
- `SingleTweak` 是一个调整函数,与 `TapTweak` 不同,它使用未标记的哈希:

`tweaked_pubkey = pubkey * sha256(tweak || pubkey) * G`

顶层树可以很容易地用于证明一组给定资产的存在、持有的资产单位总数以及持有的给定资产的总和。

`asset_id_tree_root` 值本身是另一个嵌套的 MS-SMT,结构如下:

- 键:`asset_script_key` 或 `asset_id || asset_script_key`
- 值:`asset_leaf || leaf_sum`
- sum_value: `leaf_sum`

在由给定的 `asset_id_tree_root` 作为根的树持有的 MS-SMT 中,为每个输出持有的 `asset_id` 或 `asset_group_key` 创建一个新的 Taproot Asset MS-SMT。 MS-SMT 的叶子由解锁脚本的 `asset_script_key` 或 `asset_id || asset_script_key` 键入。 资产树的根哈希计算为:

- `asset_tree_root = sha256(asset_id || left_hash || right_hash || sum_value)`

或

- `asset_tree_root = sha256(asset_group_key || left_hash || right_hash || sum_value)`

其中:

- `asset_group_key` 是从 genesis 输出点、输出索引和资产类型派生的公钥的 32 字节哈希,可用于将计划彼此具有同质性(发行同一资产的多个批次)或藏品的资产并置。

- `asset_id` 是上面指定的 32 字节资产 ID
- `left_hash` 是左子树的哈希。
- `right_hash` 是右子树的哈希。
- `amt_sum` 是每个资产叶子(本质上是 资产 UTXO)的 `amt` 值的总和。

对于给定的资产子树中的资产值的总和的承诺,允许资产持有者轻松证明他们拥有的给定资产的数量,当与资产创建和“宇宙”概念相结合使用时,允许内置的储备证明机制。

`asset_group_key` 的使用(我们将在下面看到)允许发行人将计划彼此具有同质性的资产并置在同一个资产子树中。 `asset_group_key` 的派生确保与 `asset_id` 类似,此值在链上是全局唯一的。 未指定 `asset_group_key` 的资产使用略有不同的模式来键入主 MS-SMT,并且只能以单个批次发行。

当在资产发行/铸定期间指定 `asset_group_key` 时,与顶层 SMT 类似,内部 MS-SMT 修改其内部密钥,以也考虑每个资产的派生 `asset_id`。 因此,最低级别的密钥考虑了 `asset_id` 以及 `asset_script_key`。 这再次确保所有资产和脚本密钥都放置在 MS-SMT 中的唯一位置。

请注意,由于树的结构,对于有效的 taproot 输出中的给定 Taproot Asset 子树,所有 `asset_script_key` 值**必须**是唯一的。

###### 资产叶格式

[永久链接:资产叶格式](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#asset-leaf-format)

给定 `asset_id` 的资产树的叶子提交到以 [https://github.com/lightning/bolts/blob/master/01-messaging.md#type-length-value-format TLV](https://github.com/lightning/bolts/blob/master/01-messaging.md#type-length-value-formatTLV) 格式表示的元数据的 blob,该格式由闪电网络的线路协议使用。 TLV 结构是规范的和确定性的,使其适合用于加密承诺和签名摘要。 此外,TLV 格式支持向后和向前兼容性,使得资产承诺的底层结构具有高度的可扩展性。

资产叶是一个序列化的 TLV blob,具有以下键值映射:

- 类型:0 (`taproot_asset_version`)
  - 值:
    - \[`u8`:`version`\]
- 类型:1 (`asset_id`)
  - 值:
    - \[`32*byte`:`asset_id`\]
- 类型:2 (`asset_type`)
  - 值:
    - \[`u8`:`type`\]
- 类型:3 (`amt`)
  - 值:
    - \[`BigSize`:`amt`\]
- 类型:4 (`lock_time`)
  - 值:
    - \[`BigSize`:`block_height`\]
- 类型:5 (`relative_lock_time`)
  - 值:
    - \[`BigSize`:`num_relative_blocks`\]
- 类型:6 (`prev_asset_witnesses`)
  - 值:
    - \[`u16`:`num_inputs`\]\[`asset_witnesses...`\], 其中:
      - \[`...*byte`:`asset_witnesses`\]:
        - \[`asset_witness`\]:
          - 类型:0 (`prev_asset_input`)
            - 值:\[`prev_outpoint || prev_asset_id || prev_asset_script_key`\]
          - 类型:1 (`asset_witness`)
            - 值:\[`...*byte`:`asset_witness`\]
          - 类型:2 (`split_commitment`)
            - 值:\[`...*byte`:`split_commitment_proof`\]
            - 值:\[`...*byte`:`root_asset`\]
- 类型:7 (`split_commitment_root`)
  - 值:\[`32*byte`:`split_commitment_root`\]
- 类型:8 (`asset_script_version`)
  - 值:
    - \[`u16`:`script_version`\]
- 类型:9 (`asset_script_key`)
  - 值:
    - \[`33*byte`:`pub_key`\]
- 类型:10 (`asset_group_key`)
  - 值:
    - \[`32*byte`:`pub_key`\]

其中:

- `taproot_asset_version`:是一个单字节,表示正在使用的 Taproot Asset 的版本,它允许客户端确定要期望的以下 TLV 值中的哪些。
- `asset_type`:是一个单字节,表示资产的类型,定义了两种起始资产类型:
  - `0`:普通资产
  - `1`:收藏品资产
- `amt`:是此叶位置中持有的资产数量
- `lock_time`:是一个字段,它根据包含的区块高度限制了**何时**可以移动资产。
- `relative_lock_time`:是一个字段,它根据需要从外部交易挖掘中经过的区块数限制了**何时**可以移动资产。
- `prev_asset_witnesses`:是一个**嵌套** TLV,包含验证合并到目标资产叶中所需的资产见证
  - `prev_asset_input`:通过交易中的输入位置、先前资产树的资产 ID 和资产脚本哈希来引用先前的资产输入。
    - 此值包含在资产见证本身中生成的任何签名中,其作用与普通比特币中的先前输出点类似。
    - 如果此字段全部为零,则表示正在创建**新**资产。
    - 对于**内部**拆分验证,此字段可以通过仅包含涵盖所有其他新拆分的单个签名/见证来节省空间。
    - 如果不存在此类型,则**必须**存在 `split_commitment`。
  - `split_commitment_proof`:用于允许花费因资产拆分而创建的资产 UTXO。 当资产被拆分时,非变更 UTXO 会提交到 MS-SMT 树中所有其他拆分的位置。 当花费由 asset_split 产生的变更 UTXO 时,不需要普通的 `asset_witness`,而是变更资产 UTXO 的所有者必须证明它持有由主要转移交易(`root_asset`)授权的有效拆分。
    - 具有相同 `split_commitment` 的输出被称为共享单个 `asset_witness`,因为此类输出是新资产拆分的结果。 因此,我们只需要一个见证和生成的 merkle-sum 资产树来验证转移。
  - `asset_witness`:是以与比特币的 Segwit 见证字段相同格式的序列化见证。
    - 如果 `prev_asset_input` 全部为零,则见证将是
      - 空,表示此资产不支持进一步发行。 在这种情况下,**必须**不存在 `asset_group_key`。
      - 非空,在这种情况下,将根据 [BIP-341](https://github.com/Roasbeef/bips/blob/master/bip-0340.mediawiki#specification) 验证规则解释见证,使用 `asset_group_key` 代替 `asset_script_key`。 在这种情况下,**必须**存在 `asset_group_key`。
- `split_commitment_root`:用于提交并允许验证普通资产的新输出拆分分配。 `split_commitment_root` 是一个 MS-SMT,其键为 `sha256(output_index || asset_id || asset_script_key)`,值为新的 Taproot Asset 叶。 这是一个可选字段,仅在转移期间拆分资产值时指定。
  - 具有相同 `split_commitment_root` 的输出被称为共享单个 `asset_witness`,因为此类输出是新资产拆分的结果。 因此,我们只需要一个见证和生成的 merkle-sum 资产树来验证转移。
- `asset_script_version`:是一个 2 字节资产脚本版本,用于控制如何验证以下 TLV 值。
- `asset_script_key`:是以 BIP 341 方式派生的外部公钥,该公钥可以提交到 encumbering 此资产叶的资产脚本。
- `asset_group_key`:是一个 32 字节的公钥,如 [BIP-340](https://github.com/Roasbeef/bips/blob/master/bip-0340.mediawiki) 中定义的那样。 此密钥可用于关联由其 `asset_id` 标识的不同资产,从而有效地允许进一步发行基础资产。 引用相同 `asset_group_key` 的资产将被视为相同资产。 这是一个可选字段,不包含此字段的资产实际上被认为是仅一次性发行事件,这意味着无法创建与派生 `asset_id` 相关的任何其他资产。
- `canonical_universe`:是一个键(没有相应的值),如果指定了该键,则表示链上规范宇宙的存在。 在 [./bip-tap-universe.mediawiki](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap-universe.mediawiki) 中进一步指定,规范宇宙由资产发行者维护,可用于允许第三方轻松审核资产总供应量并跟踪未来的发行。 简而言之,如果指定了此项,则资产发行期间创建的输出的下一次花费的**第二个**输出**必须**提交到基础宇宙的根哈希,并且所有后续花费必须仅在以后的资产发行事件之后发生,并且**必须**提交到新的有效宇宙根。 此功能允许轻客户端监视链上的一组输出,以便在将来资产发行时收到通知。

(TODO(roasbeef):merkle 汇总提交也超过输入集? 启用概率验证?)

资产叶用于存储与资产相关的结构化数据,以及验证资产叶的正确转移所需的一系列先前输入资产见证。 此处的输入结构类似于普通的比特币输入和输出方案,但添加了 `split_commitment`,这是允许验证者拒绝无效拆分所必需的,从而防止资产膨胀。

`asset_script_version` 是 Taproot Asset 叶的关键设计元素,因为它允许将来升级用于锁定/解锁资产叶的脚本系统。 最初,使用版本 `0` 资产叶,该版本表示 `asset_script_key` 是 BIP 341 和 BIP 342 中指定的**有效**`output_key`。 因此,版本 0 Taproot Asset VM 是在外部实例**内**的 Taproot 实例。 `asset_script_version` 的验证逻辑在 BIP ??? 中完全定义。 将来可以引入新的资产脚本版本,以进一步提高嵌入式资产脚本的表达能力。

数值高于此保留范围的类型可以用于低于 2^16-1 的 TLV 类型保留供其他 `taproot_asset_version` 迭代使用。 数值高于此保留范围的类型可用于将任意属性存储到资产。 这种属性的示例是将游戏内资产的**可变**统计数据存储在一起。 普通或收藏品资产的任何不可变字段都应改为提交到 `asset_meta_hash`,该哈希存储游戏内资产的**可变**统计数据。

MS-SMT 用于 Taproot Asset 树本身允许各方轻松验证何时引用输入时未创建任何新资产,以及每个新拆分/合并是否导致有效的拆分集(通过包含在计算的见证 sighash 中的 `split_commitment_root`)。

#### 资产创建

[永久链接:资产创建](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#asset-creation)

资产的创建类似于任何其他比特币交易,尽管它通常是 1 输入 1 输出的交易。资产创建交易花费任意一组输入,并产生一个或多个可能提交到一组新创建的资产的输出。作为一种简化机制,我们要求给定的 Taproot Asset 交易只能创建新资产或转移现有资产,但不能同时创建和转移。

(TODO(roasbeef):不允许转移+创建实际上会使事情更简单吗?)

以下函数创建一个新的有效 taproot 公钥脚本,其内部 tapscript 树提交到新资产的表示:

create_new_asset_output(total_units: uint64, asset_tag: [32]byte, genesis_point: [36]byte, asset_meta_hash: [32]byte, output_index uint32, asset_type: uint8, asset_script_key: [32]byte, taproot_asset_attrs: TLV) -> PkScript:

asset_id = sha256(
    genesis_point || sha256(asset_tag) || asset_meta_hash || output_index ||
    asset_type
)

tlv_leaf = new_taproot_asset_tlv_leaf(
    taproot_asset_version=0, asset_id, asset_type, total_units, asset_script_version=0,
    asset_script_key, attrs=taproot_asset_attrs,
)

inner_smt_leaf = new_ms_smt_leaf(
    key=asset_script_key, value=tlv_encode(tlv_leaf), sum_val=total_units,
)
inner_smt_root = ms_smt_root_hash(new_ms_smt(inner_smt_leaf))

outer_smt_leaf = new_ms_smt_leaf(
    key=asset_id, value=inner_smt_root, sum_val=total_units,
)
outer_smt_root = mew_smt_root_hash(new_ms_smt(outer_smt_leaf))

internal_key = new_internal_key()

return taproot_output_script(key=internal_key, leaves=[taproot_smt_leaf])

请注意,我们要求提前知道 `genesis_point`,以便强制执行 `asset_id` 的唯一性约束,如定义的那样。

`taproot_asset_attrs` 字段可用于提交到与资产相关联的一组任意且可能可变的字段。

在上面的示例中,我们创建的生成的 taproot 树仅提交到单个叶,即 Taproot Asset 根。实际上,人们可能会在 tapscript 树中拥有其他正常的脚本路径脚本。

上面的示例仅创建一个资产。也可以在单个输出中创建多个资产,从而批量创建资产。

#### 资产销毁

[永久链接:资产销毁](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#asset-burning)

鉴于 Taproot Asset 承诺需要在 tapscript 承诺的上下文中保持唯一性的要求,Taproot Asset 也可以被**可证明地销毁**。 这可以通过简单地从资产树中**删除**Taproot Asset 叶子并用排除证明来证明来实现。

为了使销毁更明确,更易于识别和验证,选择了“通过不可花费密钥的证明进行销毁”方法:要销毁一定数量的资产,只需将它们转移到可证明的不可花费的脚本密钥即可。 销毁证明然后看起来像任何其他状态转换证明,唯一的区别是脚本密钥可以被识别为不可花费。

这种资产销毁转换可以与同一树中的其他资产输出(例如,部分销毁的变更或其他资产)一起折叠,同时进行销毁。 并且在任何后续转移中,可以通过简单地从树中省略它们来修剪销毁的叶子,此时不需要任何额外的证明。

可以通过以下方式导出一个唯一的、可证明的不可花费的资产销毁脚本密钥:

burn_tweak = tagged_hash("TapTweak", nums_key || prev_outpoint || prev_asset_id || prev_script_key) burn_key = nums_key + burn_tweak * G


其中:

- `nums_key` 是众所周知的 NUMS 点(使用字符串“taproot-assets”和传统的“哈希和递增”方法来生成点)
- `prev_outpoint` 是根资产见证的第一个 `prev_input` 的 `outpoint`(见下文)
- `prev_asset_id` 是根资产见证的第一个 `prev_input` 的 `asset_id`(见下文)
- `prev_script_key` 是根资产见证的第一个 `prev_input` 的 `script_key`(见下文)

根资产见证的第一个 `prev_input` 定义为资产中携带先前资产见证的第一个输入。 如果资产有拆分承诺,那么它是 `prev_asset_witnesses[0].split_commitment.root_asset.prev_asset_witnesses[0].prev_asset_id`,否则它只是 `prev_asset_witnesses[0].prev_asset_id`。

以下算法可用于识别资产转移中可证明的不可花费的脚本密钥,以将其标记为资产销毁:

derive_burn_key(first_prev_id: PrevID) -> SchnorrKey burn_tweak = tagged_hash("TapTweak", NUMS_key || first_prev_id.outpoint || first_prev_id.asset_id || first_prev_id.script_key) return = NUMS_key + burn_tweak*G

get_first_prev_id(witness: AssetWitness) -> PrevID if is_split_commit_witness(witness): return witness.split_commitment.root_asset.prev_asset_witnesses[0].prev_asset_id

return witness.prev_asset_id

is_burn(asset: Asset) -> bool: first_prev_id = get_first_prev_id(asset.prev_asset_witnesses[0]) burn_key = derive_burn_key(first_prev_id)

return asset.ScriptKey == burn_key

#### 资产转移

[永久链接:资产转移](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#asset-transfers)

在普通资产和资产收藏品中,定义了两种类型的转移:交换和普通发送。

资产交换转移通过多轮交互进行,使用 PSBT 扩展(如 [./bip-tap-psbt.mediawiki](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap-psbt.mediawiki) 中定义的那样)来协同创建多输入多输出 (MIMO) 交易,该交易使用一个或多个不同的资产作为输入,并创建一个或多个新的资产所有者作为输出。

另一方面,普通发送仅涉及一轮交互,因为只有一方将资产花费给另一方的钱包。与交互式转移相比,只需要指定一个 Taproot Asset 见证。

构造和验证资产集合的一部分商品的转移需要资产的所有者从其输入转移所有权到接收者控制下的新输出中。 merkle-sum 承诺集以及资产见证有效性用于验证和认证资产转移。

常规资产的交换涉及额外的验证步骤,因为双方都需要确保不会无意中创建新资产(导致交易无效)。为了实现这一点,必须以这样一种方式形成交易,即第三方验证者能够验证拆分(将单个资产 UTXO 拆分为多个实例)和合并(将相同资产类型的输出合并为一个)。我们使用 `split_commitment` 字段来实现这一点,有效地强制了可以被认为是变更输出(在 Taproot Asset 域中)的事物,以提交到其他创建的拆分的 merkle-sum 树。

##### 资产交换交易

[永久链接:资产交换交易](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#asset-swap-transactions)

在本节中,我们指定了交互式资产转移,其中两个(或多个)参与方协同创建 MIMO 交易,该交易在一组参与方之间转移一个或多个资产。我们描述了在此设置中的核心交互、交换证明的验证。我们将关于如何将此类协议映射到基于 PSBT 的签名仪式的更多细节留给 BIP [./bip-tap-psbt-mediawiki](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap-psbt-mediawiki)。

###### 收藏品资产转移

[永久链接:收藏品资产转移](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#collectible-asset-transfers)

资产收藏品的转移比正常资产转移更简单,因为它们不需要验证拆分或合并多个资产 UTXO。 资产收藏品的转移发生在两个层面上:

- 首先,交换资产见证和脚本哈希信息,允许(每个输入资产的)接收方验证输入资产的来源,发送方将所有权委托给接收方的脚本哈希。
  - 我们称之为**内部**转移过程。
- 接下来,在较低层面上交换一组正常的比特币签名/见证,这花费所有输入的资产(有效地销毁它们)并在生成的 MIMO 交易中将资产重新创建为新的承诺。
  - 我们称之为**外部**转移过程。

请注意,并非所有输入都需要是持有 Taproot Asset 的输入。 这自然会导致新的子协议在单个交易中跨多个参与方执行批处理的 MIMO 原子交换。

由于验证是 Taproot Asset 协议的基石,因此在交互式转移过程中,每一方都执行以下一组验证断言:

- 验证任何输入资产的来源。
- 验证一方可以为每个资产生成有效的输入资产见证。
- 验证创建的新的一组 Taproot Asset 脚本输出要么不再提交到转移的资产,要么现在正确地提交到新接收的资产。

第一个验证步骤验证资产具有有效的血统。 第二步验证资产所有者如果选择,实际上可以花费该资产。 最后一步验证没有创建新资产,而是仅转移了已验证来源的现有资产。

转移指定如下:
1. 对于每个输入(可能包含一个或多个要转移的资产收藏品),所有者传输:
1. 每个输入的先前输出中存储的 MS-SMT commitment 的 opening,以 Universe 的标识符(用于提取压缩的 proof)或完整 proof 文件的形式传输。
      1. 使用此信息,资产收藏品的接收者验证:
         1. 每个 proof 都是资产树 commitment 的有效 opening,具有通往要转移资产的有效 leaf 路径。
         2. 对于每个要转移的资产,给定所需资产的 amt(对于所有资产收藏品应为 1),merkle sum commitment 有效。
         3. 给定 `asset_id`,一个有效的 opening 揭示了 `genesisOutpoint`、`assetTag` 和 `assetMeta`。
         4. 提供的 `genesisOutpoint` 存在于为一组独特的资产收藏品维护的 Universe 中。可以使用 Universe 当前 MS-SMT 的 merkle proof 或完整 proof。
2. 初始验证完成后,内部转移过程开始:
1. 对于每个要交换的资产集合 **i**:
      1. 接收者创建一个新的资产脚本密钥 commitment,`asset_script_key_i`(将用于委托输入资产的所有权),并将其发送给所有者。
      2. 所有者获取原始序列化的资产脚本,并针对 `asset_script_key_i` 脚本关闭一个新的资产 witness(作为序列化资产 leaf 的一部分)。然后将此 witness 传输给接收者。
      3. 接收者现在可以构建一个新的有效 leaf(具有委托所有权的有效 witness),或者创建一个新的 rooted 资产树(如果他们不拥有资产集合 lineage 的任何实例),或者将其添加到现有树中。称之为 `asset_leaf_i`。这个新的 leaf 必须正确引用一个有效的 `prev_asset_input` 才能成为有效的 witness。
3. 内部转移完成后,执行最终的外部转移:
1. 将一组输入(可能与资产类型有关)添加到新的版本 `2` 的 Bitcoin 交易中。
2. 交换一组新的所有权输出,并将其添加到 MIMO 转移交易中。每个参与方必须在交易中至少有一个新的所有权输出。
3. 对于每个标记为输出 **i** 的 Taproot Asset,_转移_ 资产:
      1. 发送者向接收者发送一个以新输出为根的 non-inclusion proof,证明所讨论的资产不再在其资产树中 commitment。
      2. 发送者构造一个新的有效 taproot 输出脚本,包括更新后的资产树根,并将其发送给接收者进行验证。
4. 对于每个_接收_资产的所有权输出:
      1. 接收者构造一个新的有效 taproot 输出脚本,该脚本可证明地 commitment 到新的 `asset_leaf_i` 片段。
4. 通过交换每个输入的有效 **Bitcoin** 输入 witness 集来批准外部转移。

在执行完最后一步后,双方或其中一方可以广播该交易,从而在主链中批准该交易。此外,各方还可以将其各自的资产 proof 文件(在验证过程中已完整传输)附加到其中,或者如果他们已转移资产,则将其删除。

如果 active Universe 用于转移,则只需要进行内部转移过程,并将新的 proof 上传到 Universe 以在链中盖上时间戳。

上述转移过程也可以通过以下伪代码片段表示,该代码指定了由 Alice 和 Bob 两个参与方拥有的,一系列资产的转移(完全交换):

verify_asset_input_proofs(asset_proofs: map[AssetPrevID]AssetLeafProof) -> bool

for prev_asset_input, asset_leaf in asset_proofs
    prev_outpoint, prev_asset_id, prev_asset_script_key = prev_asset_input

    match asset_leaf.proof_type:
        case FullProof:

            for i in range(len(asset_leaf.inclusion_proofs)):
                asset_leaf_tlv = asset_leaf.raw_leaf[i]
                leaf_merkle_proof = asset_leaf.inclusion_proof2[i]

                if i != 0 and asset_leaf_tlv.prev_input.prev_outpoint !=
                    asset_leaf[i-1].leaf_merkle_proof.outpoint:
                    fail

                if not verify_inclusion_proof(leaf_merkle_proof, asset_leaf):
                    fail

                if not verify_witness(asset_leaf.asset_witness, asset_leaf):
                    fail

        case CompactProof:
            if not verify_universe_proof(asset_leaf.inclusion_proofs, prev_asset_id):
                fail

transfer_assets(sender_assets: map[AssetID]AssetLeaf, receiver_scripts: [[32]byte]) -> map[AssetID]AssetLeaf

new_assets = {}
for prev_asset_input, asset_leaf in sender_assets:
    asset_script_key = asset_script_keyes[i]

    new_leaf = clone_unique_leaf(asset_leaf)
    new_leaf.asset_script_key = asset_script_key
    new_leaf.prev_asset_input = prev_asset_input
    new_leaf.asset_witness = gen_witness(tlv_encode(new_leaf))

    new_assets[prev_asset_input.prev_asset_id] = new_leaf

return new_assets

taproot_asset_interactive_transfer(bob_inputs_assets: map[AssetID]AssetLeafProof, alice_input_assets: map[AssetID]AssetLeafProof, alice_internal_key: PublicKey, bob_internal_key: PublicKey, alice_asset_script_keyes: [[32]byte], bob_asset_script_keyes: [[32]byte]) -> Tx:

if !verify_asset_input_proofs(list(chain(alice_new_assets, bob_input_assets))):
  fail

bob_new_assets = transfer_assets(alice_input_assets, bob_asset_script_keyes)
alice_new_assets = transfer_assets(bob_input_assets, alice_asset_script_keyes)

alice_new_taproot_asset_root = alice_compute_root(remove=alice_input_assets)
if not verify_non_inclusion(alice_new_taproot_asset_root, bob_new_assets):
  fail

bob_new_taproot_asset_root = bob_compute_root(remove=bob_input_assets)
if not verify_non_inclusion(bob_new_taproot_asset_root, alice_new_assets):
  fail

transfer_tx = new_tx()
for prev_asset_input, _ in list(chain(alice_input_assets, bob_inputs_assets)):
    transfer_tx.add_txin(prev_asset_input.prev_outpoint)

transfer_tx.add_output(taproot_output_script(key=alice_internal_key, leaves=[alice_new_taproot_asset_root]))
transfer_tx.add_output(taproot_output_script(key=bob_internal_key, leaves=[bob_new_taproot_asset_root]))

return transfer_tx

上面的方法生成一个完全签名的 Bitcoin 交易,当广播时,将 **原子地** 将 Alice 的一套收藏品资产交易为 Bob 的一套收藏品资产,Alice 另外向 Bob 支付 1 BTC,以满足他们的转移条件。

###### 常规资产转移

[Permalink: 常规资产转移](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#normal-asset-transfers)

常规资产的转移与资产收藏品的转移几乎相同。主要的区别在于,双方还需要验证任何输入资产的正确拆分和合并。

举例来说,假设 Alice 拥有 10 个单位的资产 Foo,并希望将其中 9 个单位转移给 Bob。当生成资产 witness 以转移资产时,Alice 的 witness commitment 到一个新的 merkle-sum split 树,证明她的新 leaf 是该树的成员,并且该树仍然 commitment 到只有 10 个单位的资产。Alice 可能不知道最终的结构,但添加了一个额外的约束,即存在此 commitment。只有满足此条件,常规资产的有效转移才有效。

上面的例子演示了如何验证 **外部拆分**(跨不同的 taproot 输出的拆分)。除此之外,我们还需要验证在资产 commitment 中没有创建新的资产。我们使用 SMT 的 merkle-sum 特性来验证这一点。

也就是说,常规资产的转移与收藏品资产的转移相同,但有以下附加项:

1. 内部转移验证:
1. 对于每个资产 **i** 和金额 **n**,要交换:
      1. 发送者传输一个有效的 MS-SMT merkle proof,证明该资产的存在,以及要转移金额的真实性。
      2. 接收者像往常一样创建一个新的 `asset_script_key_i` 和 `asset_leaf_i`,并添加约束,即新资产的 `amt` 字段必须与要转移的金额匹配。
      3. 当为给定的资产输入生成有效的 `asset_witness` 时,发送者还必须构造一个新的 MS-SMT 树,其 key 为 `sha256(output_index || asset_id || asset_script_key)`,value 为正在创建的资产 leaf(序列化时没有此字段)。这将是更改输出的 `split_commitment_root`。
2. 外部转移:
1. 对于每个所有权输出 **i**,转移资产 **y** 的 **n** 个单位:
      1. 发送者不再需要传输完整的 non-inclusion proof,而是打开其更改输出的 Taproot Asset root commitment,从而使接收者可以验证金额 `t-n` 已被 commitment,其中 `t` 是先前的资产根总和。
      2. 对于与输入拆分关联的每个新资产 leaf,验证序列化的 leaf 是否是更改输出中 `split_commitment_root` 的成员。

请注意,对于交易中给定的输入 `asset_id`,任何产生的内部拆分将共享相同的输入 witness(间接引用)以及 `split_commitment_root`。

以下伪代码例程定义了创建和验证 `split_commitment_root` 的新方法:

create_split_commit_root(asset_splits: map[SplitLocator]SplitLeaf) -> [32]byte:

split_tree = new_mt_smt() for split_locator, split_leaf in range asset_splits: output_index, asset_id, asset_script_key, split_amt = split_locator split_key = sha256(output_index || asset_id || asset_script_key)

   split_tree.insert(key=split_tree, value=split_leaf, sum_val=split_amt)

return split_tree.root_hash()

verify_split_commit_root(split_loc: SplitLocator, split: SplitLeaf, split_root: [32]byte, audit_path: [[32]byte]) -> bool:

output_index, asset_id, asset_script_key, split_amt = split_locator
split_key = sha256(output_index || asset_id || asset_script_key)

split_leaf = new_mt_smt_leaf(key=split_leaf, val=split, sum_val=split_amt)

hash_val = split_leaf
for branch in audit_path:
    branch_sum = split_leaf.sum_val + branch.sum_val

    hash_val = sha256(hash_val || branch.hash || branch+sum)

return hash_val == split_root

##### 常规资产转移

[Permalink: 常规资产转移](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#normal-asset-transfers-1)

Normal active 资产转移 are single sided transfers where only a single
party is transmitting a collection or normal asset to another party. As a
result, a MIMO transaction isn't necessary as given the asset in question,
amount to be transferred, and the desired `asset_script_key` along
with a public key, a new asset root and its corresponding taproot output can be
constructed.

Non-interactive transfers introduce the concept of a on-chain Taproot Asset
**地址**。See [bip-tap-addr](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-bap-addr.mediawiki) for further details
on the address format.

给定一个有效的 Taproot Asset 地址,如果 Alice 希望使用 Taproot Asset 地址 **C** 将资产 **Y** 的 **N** 个单位转移给 Bob:

- Alice 使用 Taproot Asset 地址来派生构造一个有效的 leaf,以及一个由 [BIP-341](https://github.com/Roasbeef/bips/blob/master/bip-0341.mediawiki) 指定的新的外部 taproot 输出。
- Alice 在她的资产树中构造一个新的 sub-commitment,现在 commitment 到资产的 `T-N` 个单位(在正常资产的情况下)。
- Alice 签名并广播一个包含两个输出的新交易,其中必须包含 **K** satoshis 的存款金额。

Alice 的内部转移不包括 Bob 的新资产 leaf 的 `prev_asset_input` 或资产 witness。相反,Bob 将使用引用的 `split_commitment_root` 来创建一个 `split_commitment_proof`,以声明金额 `N` 的新拆分的存在。此转移有效,因为 Alice 的资产 witness 的“sig hash”也涵盖了 Bob 新资产 commitment 的结构。

对于 non-interactive transfers,Bob 需要从某个地方获得此 proof,但是可以完全根据 Alice 的 non-change 输出的最新 proof 来重建它。如果 Alice 希望在链上将此数据传输给 Bob,则她可以将数据放在 Taproot 当前未使用的 annex 字段中。

就这样。Alice 可以构造 Bob 在链中寻找的预期根 Taproot Asset commitment。这使得该方案对轻客户端友好,因为中微子节点可以简单地在过滤器中查找生成的 taproot 输出。“存款”金额是必要的,因为 Bitcoin 不允许零值输出。此金额只需要略高于灰尘,可以看作是一种固定的转移费用。

为了能够 **花费** 该资产,Bob 需要获得用作输入的完整资产 proof,该 proof 可以从相关的 Universe 获得,也可以直接从 Alice 获得。

non_interactive_send(receiver_script_key: [32]byte, receiver_internal_key: PublicKey, input_asset: AssetLeaf, amt: uint64) -> Tx

receiver_leaf = clone_leaf(input_asset.leaf)
receiver_leaf.asset_script_key = receiver_script_key
receiver_leaf.prev_input = nil
receiver_leaf.amt = amt

inner_smt_leaf = new_ms_smt_leaf(
    key=receiver_script_key, value=tlv_encode(receiver_leaf), sum_val=amt,
)
inner_smt_root = ms_smt_root_hash(new_ms_smt(inner_smt_leaf))
outer_smt_leaf = new_ms_smt_leaf(
    key=input_asset.asset_id, value=inner_smt_root, sum_val=amt,
)
outer_smt_root = mew_smt_root_hash(new_ms_smt(outer_smt_leaf))

internal_key = new_internal_key()

receiver_output = taproot_output_script(key=internal_key, leaves=[taproot_smt_leaf])


为了能够 **花费** 这个新资产,Bob 需要获得资产的完整来源 proof。鉴于 Bob 能够找到链上的转移交易(使用诸如 BIP 157/158 之类的系统),Bob 知道存储资产的先前输入。给定一个已知的 Universe,Bob 可以查找先前的 outpoint,然后将他的新 leaf 信息附加到文件的末尾。

##### Taproot Asset 文件 & Leaf 验证

[Permalink: Taproot Asset 文件 & Leaf 验证](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#taproot-asset-files--leaf-verification)

Taproot Asset 文件可用于气密地存储和传输给定资产的来源 proof。该平面文件是在主 Bitcoin 链中以及在 holding 资产 commitment 的 Taproot 输出中的一系列 merkle proof。为了验证资产的有效性和来源,验证者在资产交易图中向后(或向前)走,验证 along the way 的每个 commitment 和资产 witness 状态转换。

Taproot Asset proof 文件格式在 [./bip-tap-proof-file.mediawiki](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap-proof-file.mediawiki) 中指定。proof 文件的未来迭代也可能会 commitment 到每个单独 proof 段的根 append-only merkle 树根。这将允许对资产的来源进行概率验证,从而降低第三方和潜在资产接收者的验证成本。

#### 资产 Universes

[Permalink: 资产 Universes](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#asset-universes)

对资产的验证还必须验证资产的来源,即该资产是创建该资产本身的初始 genesis outpoint 的间接后代。由于所有资产都由其来源定义,因此无法验证资产的历史会破坏系统的全部目的。例如,Bitcoin 链被定义为最终链接回主 genesis block 的所有 block,如果一条链不包括 genesis block,那么它就不是 Bitcoin。

Universe 概念是一个链上(以及链下)MS-SMT 索引,可索引到主链中,该索引索引了一组已披露的 proof,并将它们 anchor 回主链。Universes 用于引导资产的来源,也可以迭代以(重新)构造资产的 proof 文件。

Universes 在 [./bip-tap-universe.mediawiki](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap-universe.mediawiki) 中完全指定。

#### 多跳 Taproot Asset 转移

[Permalink: 多跳 Taproot Asset 转移](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#multi-hop-taproot-asset-transfer)

利用嵌入式资产 HTLC/PTLC 构造,我们可以扩展 Lightning Network 以支持任意资产的多跳转移,并将网络的 Bitcoin backbone 用作与资产无关的货币传输网络。多跳支付的发送者和接收者只需要知道要转移的资产。网络的内部 backbone 仅看到等效的 Bitcoin 流。

假设 Bob 有 **N** beefbux 的出站流动性,而 Alice 有 **M** beefbux 的入站流动性(其中 `N>M`),那么 Bob 可以向 Alice 发送 **M** beefbux。转移的第一跳获取 **M+f** beefbux(其中 **f** 是他们的费用),并发送 `K = M/B` BTC,其中 **B** 是约定的/已公布的 beefbux/BTC 汇率。转移的所有最后一跳都获取 **K** BTC,并将 **M** beefbuf(在实际路由中,由于费用会更少)发送给 Alice。

通过以上构造,可以将 Lightning Network 扩展为支持任意资产的转移,其中 BTC 有效地充当“gas 资产”。

Lightning Network (BOLT) 扩展的完整详细信息在 bLIP ??? 中指定。

### 应用

[Permalink: 应用](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#applications)

### 测试向量

[Permalink: 测试向量](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#test-vectors)

[Asset Leaf Format](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/Asset%20Leaf%20Format) 的测试向量可以在这里找到:

- [Asset TLV encoding 测试向量](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap/asset_tlv_encoding_generated.json)
- [Asset TLV encoding 错误测试向量](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap/asset_tlv_encoding_error_cases.json)
- [Asset burn key 测试向量](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap/asset_burn_key_generated.json)

测试向量由 [Taproot Assets GitHub 存储库中的单元测试](https://github.com/lightninglabs/taproot-assets/tree/main/asset) 自动生成。

### 向后兼容性

[Permalink: 向后兼容性](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#backwards-compatibility)

### 致谢

[Permalink: 致谢](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#acknowledgement)

感谢 Peter Todd 多年来普及了 Taproot Asset 设计中使用的许多想法和技术。该系统设计的各个组件受到了他早期在诸如 proofchains 之类的系统上的工作的启发。

感谢 Giacomo Zucco、Alekos Filini 和 Maxim Orlovsky(以及 RGB 设计师的其余人员),感谢他们率先使用客户端验证技术来创建资产发行协议的概念。

感谢 Daniel Stadulis 阅读了本草案的非常早期的版本,并在早期的设计讨论会中塑造了设计的许多组件。

### 参考实现

[Permalink: 参考实现](https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#reference-implementation)

github.com/lightninglabs/taproot-assets

你目前无法执行该操作。

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

0 条评论

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