1
0
Fork 0
mirror of https://github.com/bitcoin/bips.git synced 2025-03-04 03:03:53 +01:00

bip-tap: BIPs for the Taproot Assets Protocol

This commit is contained in:
Olaoluwa Osuntokun 2021-12-15 19:20:54 -08:00
parent e643d247c8
commit c156b7691d
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
23 changed files with 94843 additions and 0 deletions

182
bip-tap-addr.mediawiki Normal file
View file

@ -0,0 +1,182 @@
<pre>
BIP: ???
Layer: Applications
Title: Taproot Asset On Chain Addresses
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
</pre>
==Abstract==
This document describes a way to map a single-asset Taproot Asset send to a
familiar <code>bech32m</code> address, as well as a way to map that address into
a valid Taproot Asset script tree that can be included in a broadcast
transaction to complete a transfer.
Once the transaction has been broadcast, the receiver can use the
previous outpoint of the confirmed transaction to lookup the complete asset
proof in their chosen Universe.
==Copyright==
This document is licensed under the 2-clause BSD license.
==Motivation==
The Taproot Asset protocol needs an easy way to allow users to send each other
assets on-chain, without requiring several rounds of interaction to exchange and
validate proofs. By using the existing <code>bech32m</code> address
serialization standard, such addresses look distinct, while also looking
familiar enough based on the character set encoding. The described address
format also addresses a number of possible foot guns, by making it impossible
to send the wrong asset (based on an address) amongst other protections.
==Specification==
A Taproot Asset is uniquely defined by its <code>asset_genesis</code> as well as
the <code>asset_script_key</code> that serves as a predicate that must be
satisfied for transfers. These values, along with an internal Taproot key used
when creating the Bitcoin output that holds the Taproot Asset, are encoded into
a single address.
===Encoding an Address===
Let the human readable prefix (as specified by BIP 173) be:
* <code>tapbc</code> for mainnet
* <code>taptb</code> for testnet
* <code>taprt</code> for regtest
* <code>taptb</code> for the public signet
* <code>tapsb</code> for simnet
We refer to this value as the <code>taproot_asset_hrp</code>
Given the 32-byte <code>asset_id</code>, 33-byte compressed
<code>asset_script_key</code>, and 33-byte compressed internal public
key, 8-byte amount to send, an address is encoded as:
* <code>bech32m(hrp=taproot_asset_hrp, addr_tlv_payload)</code>
where <code>addr_tlv_payload</code> is a TLV payload composed of the following
types:
* type: 0 (<code>taproot_asset_version</code>)
** value:
*** [<code>u8</code>:<code>version</code>]
* type: 2 (<code>asset_id</code>)
** value:
*** [<code>32*byte</code>:<code>asset_id</code>]
* type: 3 (<code>asset_key_family</code>)
** value:
*** [<code>33*byte</code>:<code>family_key</code>]
* type: 4 (<code>asset_script_key</code>)
** value:
*** [<code>33*byte</code>:<code>script_key</code>]
* type: 6 (<code>internal_key</code>)
** value:
*** [<code>33*byte</code>:<code>taproot_internal_key</code>]
* type: 7 (<code>taproot_sibling_preimage</code>)
** value:
*** [<code>...*byte</code>:<code>tapscript_preimage</code>]
* type: 8 (<code>amt</code>)
** value:
*** [<code>BigSize</code>:<code>amt_to_send</code>]
* type: 10 (<code>proof_courier_addr</code>)
** value:
*** [<code>...*byte</code>:<code>proof_courier_addr</code>]
Inspired by Lightning's BOLT specification, we adopt the "it's OK to be odd"
semantics here as well. This enables receivers to specify to the caller certain
information that MUST be known in order to properly complete a transfer.
The only odd keys specified in the current version are the
<code>asset_key_family</code> type and the <code>asset_type</code> field. The
<code>asset_key_family</code> field isn't always needed for assets that don't
allow for continual re-issuance. Similarly, if the <code>asset_type</code>
field isn't specified, then one can assume a normal asset is being sent.
The <code>proof_courier_addr</code> is a mandatory URI (RFC 3986) that indicates
what proof courier to use when sending the proofs from the sender to the
recipient. The scheme (protocol) indicates the type of courier transport to use,
current valid values are <code>hashmail://</code> for Hashmail based couriers
and <code>universerpc://</code> for gRPC based transfer via a universe server.
===Decoding and Sending To An Address===
Given a valid Taproot Asset address, decompose the contents into the referenced
<code>asset_id</code>, <code>asset_script_key</code>, and
<code>internal_key</code>. Look up the full <code>asset_genesis</code> with the
<code>asset_id</code> in the appropriate Universe.
Construct a new blank Taproot Asset leaf according to the default
[[./bip-tap.mediawiki#asset-leaf-format|Asset Leaf Format]] with the following
values being set explicitly (and all other values being their default/zero
values):
* <code>taproot_asset_version</code>: <code>0</code>
* <code>asset_genesis</code>: <code>asset_genesis</code>
* <code>amt</code>: <code>amt_to_send</code>
* <code>asset_script_version</code>: <code>0</code>
* <code>asset_script_key</code>: <code>asset_script_key</code>
* <code>asset_key_family</code>: <code>asset_key_family</code>
Create a valid tapscript root, using leaf version <code>0x0c</code> with the
sole leaf being the serialized TLV blob specified above.
Create the top-level taproot public key script, as a segwit v1 witness
program, as specified in BIP 341, using the included key as the internal key.
With the target taproot public key script constructed, the asset is sent to the
receiver with the execution of the following steps:
# Construct a valid transaction that spends an input that holds the referenced <code>asset_id</code> and ''exactly'' <code>amt</code> units of the asset.
# Create a new Taproot Asset output commitment based on the input commitment (this will be the change output), that now only commits to <code>S-A</code> units of <code>asset_id</code>, where <code>S</code> is the input amount, and <code>A</code> is the amount specified in the encoded Taproot Asset address.
## This new leaf MUST have a <code>split_commitment</code> specified that commits to the position (keyed by <code>sha256(output_index || asset_id || asset_script_key)</code> within the transaction of the newly created asset leaf for the receiver. This split commitment is omitted by the sender when serializing the leaf for inclusion in the asset tree, otherwise the tree wouldn't be predictable on the receiver side. This has a corresponding rule in the [[./bip-tap-vm.mediawiki|bip-tap-vm]] during the input mapping of the inclusion proof validation.
## Add an additional output that sends a de minimis (in practice this MUST be above dust) amount to the top-level taproot public key computed earlier.
## Broadcast and sign the transaction, submitting the resulting Taproot Asset state transition proof to a Universe of choice, also known by the receiver.
# Post the resulting state transition proof to the specified Universe. The submitted proof ''must'' contain the optional auxiliary value of the full <code>split_commitment</code> the receiver requires to spend the asset.
===Non-interactive full value send===
Sending assets to an address is inherently a non-interactive process as there is
no active communication between the sender and recipient other than the exchange
of the address in the first place.
Because of the above mentioned requirement that an asset leaf created to send to
an address MUST have a <code>split_commitment</code>, a special case exists if
there is no change going back to the sender (an asset output is fully consumed
by the transfer to an address): A special ''tombstone'' output with a value of
0 must be created for the split root asset (the <code>root_asset</code> of the
split) that holds the transfer witness. The <code>script_key</code> of the
split root asset output should be the well-known NUMS point (using the string
"taproot-assets" and the traditional "hash and increment" approach to generating
the point) to prove the output cannot be spent further. Such a tombstone output
can then be pruned from the tree when the UTXO is spent further.
More details about interactive and non-interactive sends and tombstone outputs
can be found in the [[./bip-tap-psbt.mediawiki|bip-tap-psbt]].
===Spending The Received Asset===
In order to spend (or simply confirm receipt) of the received asset, the
receiver should:
# Re-derive the taproot public key script created above that sends to their specified Taproot Asset leaf.
# Wait for a transaction creating the output to be confirmed in the blockchain.
## In practice this may be via light client protocols such as BIP 157/158, or simply a full node with an address index, or import public key.
# For each previous outpoint referenced in the transaction:
## Look up the previous outpoint as a key into the chosen canonical Universe/Multiverse.
### If the key is found, verify the inclusion proof of the value (as described in [[./bip-tap-proof-file.mediawiki|bip-tap-proof-file]]), and extract the <code>split_commitment</code> inclusion proof for the output.
# Walk the Universe tree backwards in time to incrementally construct the full provenance proof needed to spend the asset.
==Test Vectors==
Test vectors for [[Encoding an Address]] can be found here:
* [[bip-tap-addr/address_tlv_encoding_generated.json|Address TLV encoding test vectors]]
* [[bip-tap-addr/address_tlv_encoding_error_cases.json|Address TLV encoding error test vectors]]
The test vectors are automatically generated by
[https://github.com/lightninglabs/taproot-assets/tree/main/address unit tests in
the Taproot Assets GitHub repository].
==Reference Implementation==
github.com/lightninglabs/taproot-assets/tree/main/address

View file

@ -0,0 +1,65 @@
{
"error_test_cases": [
{
"address": {},
"error": "missing chain params HRP"
},
{
"address": {
"chain_params_hrp": "bc"
},
"error": "invalid chain params HRP"
},
{
"address": {
"chain_params_hrp": "tapbc"
},
"error": "missing asset ID"
},
{
"address": {
"chain_params_hrp": "tapbc",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000"
},
"error": "missing script key"
},
{
"address": {
"chain_params_hrp": "tapbc",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "0000000000000000000000000000000000000000000000000000000000000000"
},
"error": "invalid script key length",
"comment": "script key must be 33 bytes (compressed)"
},
{
"address": {
"chain_params_hrp": "tapbc",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"error": "missing internal key"
},
{
"address": {
"chain_params_hrp": "tapbc",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
"internal_key": "0000000000000000000000000000000000000000000000000000000000000000"
},
"error": "invalid internal key length",
"comment": "internal key must be 33 bytes (compressed)"
},
{
"address": {
"chain_params_hrp": "tapbc",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
"internal_key": "000000000000000000000000000000000000000000000000000000000000000000",
"group_key": "0000000000000000000000000000000000000000000000000000000000000000"
},
"error": "invalid group key length",
"comment": "group key must be 33 bytes (compressed)"
}
]
}

View file

@ -0,0 +1,110 @@
{
"valid_test_cases": [
{
"address": {
"chain_params_hrp": "taprt",
"asset_version": 0,
"asset_id": "7a3811630bb33503c6536c3a223d3caecb93fe55f4b3439528edf27b10d38e93",
"group_key": "",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "",
"amount": 5577006791947779410,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "taprt1qqqsqq3q0gupzcctkv6s83jndsazy0fu4m9e8lj47je589fgahe8kyxn36fsgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lf4jcygg8ln74yz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xseszxcn5n",
"comment": "valid regtest address"
},
{
"address": {
"chain_params_hrp": "tapsb",
"asset_version": 0,
"asset_id": "8acb5154261425dd613fda19dee00a51e95c6921df8af4085bc468706b946fec",
"group_key": "",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "",
"amount": 3510942875414458836,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "tapsb1qqqsqq3q3t94z4pxzsja6cflmgvaacq22854c6fpm790gzzmc358q6u5dlkqgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lxzu4luvrc3cagz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xses89l6tn",
"comment": "valid simnet address"
},
{
"address": {
"chain_params_hrp": "taptb",
"asset_version": 0,
"asset_id": "60459cbb4d4e6a78b8c58545f2fe026ad217bf0fafeed5ff5e3b3379c658ddf3",
"group_key": "",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "",
"amount": 2740103009342231109,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "taptb1qqqsqq3qvpzeew6dfe483wx9s4zl9lszdtfp00c04lhdtl678vehn3jcmhesgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lycrv626h62fy2z32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xsesdgef4w",
"comment": "valid testnet address"
},
{
"address": {
"chain_params_hrp": "tapbc",
"asset_version": 0,
"asset_id": "f2c70e1261b761f098499918acf6ccf18d7d9cf7cd6be0c940630f0643ab832c",
"group_key": "",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "",
"amount": 545291762129038907,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "tapbc1qqqsqq3q7trsuynpkaslpxzfnyv2eakv7xxhm88he447pj2qvv8svsatsvkqgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lq7g58al55hhrkz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xsesu23fxd",
"comment": "valid mainnet address"
},
{
"address": {
"chain_params_hrp": "taptb",
"asset_version": 0,
"asset_id": "7f3a94b3048ecbce4f2b1686e2df89bde52d5ead1aed011f75fa6578dcab0839",
"group_key": "03f32d239904d1addae728d1917a94bc1d20455b12b251a9222d035e5014a9f759",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "",
"amount": 1,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "taptb1qqqsqq3q0uaffvcy3m9uunetz6rw9hufhhjj6h4drtksz8m4lfjh3h9tpqusxggr7vkj8xgy6xka4eeg6xgh499ur5sy2kcjkfg6jg3dqd09q99f7avsgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssqgppg4xsctndpkkz6tv8ghj7unpdejzu6rpwd5x6ctfdsh8qun0danzucm0w4exjetj8g6rgvcxm4yl6",
"comment": "signet group collectible"
},
{
"address": {
"chain_params_hrp": "tapsb",
"asset_version": 0,
"asset_id": "7da00bc74bfe9791807fa20dbeec226348904e6bfa8c10ab434922369e4d4747",
"group_key": "",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "",
"amount": 1,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "tapsb1qqqsqq3q0ksqh36tl6terqrl5gxmampzvdyfqnntl2xpp26rfy3rd8jdgarsgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssqgppg4xsctndpkkz6tv8ghj7unpdejzu6rpwd5x6ctfdsh8qun0danzucm0w4exjetj8g6rgvcvmghpa",
"comment": "simnet collectible"
},
{
"address": {
"chain_params_hrp": "tapsb",
"asset_version": 0,
"asset_id": "b603ddaafac3b6253de23ae01935f108bee96363eddf77456c0e24ed6a67650f",
"group_key": "",
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"tapscript_sibling": "00c0126e6f7420612076616c696420736372697074",
"amount": 1,
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
},
"expected": "tapsb1qqqsqq3qkcpam2h6cwmz200z8tspjd03pzlwjcmrah0hw3tvpcjw66n8v58sgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78sw9gqcqfxumm5ypsjqanpd35kggrnvdexjur5pqqszz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xseswj02c5",
"comment": "simnet collectible with sibling"
}
],
"error_test_cases": null
}

323
bip-tap-ms-smt.mediawiki Normal file
View file

@ -0,0 +1,323 @@
<pre>
BIP: ???
Layer: Applications
Title: Merkle Sum Sparse Merkle Trees
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
</pre>
==Abstract==
This document describes a merkle-sum sparse merkle tree (MS-SMT) data
structure. This is an augmented version of a sparse merkle tree that includes
a sum value which is combined during the internal branch hashing operation.
Such trees permit efficient proofs of non-inclusion, while also supporting
efficient fault proofs of invalid merkle sum commitments.
==Copyright==
This document is licensed under the 2-clause BSD license.
==Motivation==
Taproot Assets are a Taproot-native asset overlay protocol. Rather than post all
asset related data on-chain in <code>OP_RETURN</code> outputs, the protocol
instead uses a series of commitments anchored within the Taproot script tree.
When handling unique assets, it's important to be able to prove that the former
owner (or seller) of the asset is no longer committing to it within their tree.
Additionally, when carrying out multi-asset swaps, verifiers need to be able to
efficiently verify that no new assets are being created (inflation check). The
MS-SMT supports both non-inclusion proofs, and non-inflation proofs.
==Design==
A merkle sum tree is a merkalized key-value map simulated over a particia
merkle tree of depth 256 (as we use sha256 as our hash function). The "base"
state of the tree, is a merkle tree with 2^256 leaves, storing an "empty hash".
Within this tree, the digests of an empty leaf, and empty internal nodes for
each level can be computed ahead of time. The "value" of an empty leaf is zero.
In addition to storing the hash digest of a leaf/branch, an 8-byte value is
also stored along side the entry, making each entry 40 bytes in length. The
root hash therefore commits to the digest of all items in the leaf, as well as
the sum of all the "sum values" in the set of leaves. When combining two
branches/leaves, the sum of the left and right leaf/branch is serialized along
with the hash digest of the nodes.
When inserting a new key into the tree, at each level, the ith bit of the key
is used to traverse left or right down the tree. Due to this traversal, every
possible key has a unique location (position wise) within the set of leaves. A
non-inclusion proof is the proof that the value at the unique position for a
key is empty.
Due to the nature of the mapping, sparse merkle trees are ''history
independent'' meaning no matter the inserting order, given the same set of keys
and values, the same root hash will always be produced. As the size of the
tree is intractable, a series of techniques are used to maintain a relevant set
of branches and leaves in memory, using a persistent key-value store to store
the relevant unique items of the tree. Proofs can be compressed by using a
bitmap to indicate if the next node in the proof is an empty hash for that
level, or the parent of the item being proved.
===Specification===
We use <code>sha256</code> as our hash function, and 8-byte sum values.
====Building the Empty Hash Map====
The map of all empty hashes by level <code>empty_hashes</code> can be
pre-computed ahead of time, as:
* The hash of an empty leaf is <code>empty_hash_1 = sha256(nil, nil)</code>
* The hash of an empty branch at the second level is <code>empty_hash_2 = sha256(empty_hash_1, empty_hash_1)</code>
* and so on...
We refer to the map resulting from this route as the
<code>empty_hash_map</code>:
<source lang="python">
build_empty_hash_map() -> map[int][32]byte:
empty_hash_map = make(map[int][32]byte)
prior_level_hash = None
for i in range(256):
if prior_level_hash is None:
prior_level_hash = sha256(nil, nil, 0)
empty_hash_map[i] = prior_level_hash
continue
empty_hash_map[i] = sha256(prior_level_hash, prior_level_hash, 0)
return empty_hash_map
</source>
====Node Digest Computation===
The MS-SMT tree has two types of nodes: leaf nodes and branch nodes.
The digest of a leaf node is a function of the <code>sum_value</code> (encoded
as a big-endian integer) of the leaf node and it's actual <code>value</code>:
<source lang="python">
leaf_node_digest(leaf_node: MerkleSumLeaf) -> [32]byte:
h = new_sha_writer()
h.write_bytes(leaf_node.value)
h.write_big_endian_int(leaf_node.sum_value)
return h.bytes()
</source>
The digest of a branch node commits to the digest of its two children (which
may be another branch or a leaf), and also commits to the _sum_ of their
respective <code>sum_value</code>s:
<source lang="python">
node_digest(node: Node) -> [32]byte
match node:
case MerkleSumLeaf:
return leaf_node_digest(node)
case MerkleSumBranch:
return branch_node_digest(node)
branch_node_digest(left: Node, right: Node) -> [32]byte
left_digest = node_digest(left)
right_digest = node_digest(right)
new_sum = left.sum_value() + right_sum_value()
h = new_sha_writer()
h.write_bytes(left_digest)
h.write_bytes(right_digest)
h.write_big_endian_int(new_sum)
return h.bytes()
</source>
====Looking Up Items====
Looking up an item in the tree requires traversal down the tree based on the
next bit position of the key itself. We assume the existence of a persistent
key-value store that maps the hash of a node to the left and right digests of
its children.
The following routine specifies the lookup algorithm:
<source lang="python">
lookup_item(key [32]byte, db KVStore) -> MerkleSumLeaf:
root_hash, _ = db.fetch_root_hash()
current_branch = root_hash
value_hash, value_sum = None
for i in range(256):
if bit_index(i, key) == 0:
current_branch, _ = db.get_children(current_branch)
else:
_, current_branch = db.get_children(current_branch)
return MerkleSumLeaf(current_branch.hash, current_branch)
</source>
====Inserting Items====
Inserting items into the tree entails traversing the tree until we arrive at
the position for the leaf, then bubbling up (hashing and summing) the change
all the way up the tree.
<source lang="python">
insert_item(key [32]byte, value []byte, sum_value int64, db KVStore) -> None:
root_hash, _ = db.fetch_root_hash()
current_branch = root_hash
insertion_path = []
value_hash, value_sum = None
for i in range(256):
if bit_index(i, key) == 0:
current_branch, sibling = db.get_children(current_branch)
insertion_path.append(sibling)
else:
sibling, current_branch, = db.get_children(current_branch)
insertion_path.append(sibling)
db.insert(current_branch.parent_hash, MerkleSumLeaf(key, value, sum_value))
for i in range(256):
updated_sum = sum_value + inclusion_path[-1].value
sibling_node = insertion_path[-1]
if bit_index(i, key) == 0:
updated_value = sha256(value, sibling_node.sum_value, updated_sum)
db.insert(key=updated_value, value=(sibling_node, value))
else:
updated_value = sha256(insertion_path[-1].hash, value, updated_sum)
db.insert(key=updated_value, value=(value, sibling_node))
value = updated_value
sum_value = updated_sum
insertion_path.pop()
return None
</source>
====Deleting Items====
Deleting an item is identical to insertion, but we delete the item in the tree
by setting its value to the empty hash.
<source lang="python">
delete_item(key [32]byte, db KVStore) -> None:
return insert_item(key, nil, 0, db)
</source>
====Creating Inclusion & Non-Inclusion Proofs====
An inclusion proof of an item proves that the item is found in the tree, and
has a certain sum value. A non-inclusion tree proves the opposite: that an item
is not found within the tree.
Generating an inclusion or non inclusion proof entails walking down the tree
and obtaining all the sibling hashes and their sum values:
<source lang="python">
gen_merkle_proof(key [32]byte, db KVStore) -> []MerkleSumNode
root_hash, _ = db.fetch_root_hash()
current_branch = root_hash
proof_nodes = []
value_hash, value_sum = None
for i in range(256):
if bit_index(i, key) == 0:
current_branch, sibling = db.get_children(current_branch)
proof_nodes.append(sibling)
else:
sibling, current_branch, = db.get_children(current_branch)
proof_nodes.append(sibling)
return proof_nodes
</source>
A plain proof is always a series of 256 merkle sum elements. However we can
compress proofs by using an extra bitmap that indicates if the proof contents
are an empty hash or not.
<source lang="python">
compress_merkle_proof(proof []MerkleSumNode) -> CompressedProof:
compressed_proof = new_compressed_proof(
compression_bits=new_bit_vector(256),
proof=[]MerkleSumNode{},
)
for i, proof_node in proof:
if proof_node == empty_hash_map[i]:
compressed_proof.compression_bits.append(1)
else:
compressed_proof.proof.append(proof_node)
return compressed_proof
</source>
====Verifying Inclusion & Non-Inclusion Proofs====
In order to verify a proof, we need to confirm that if starting at the proof,
if we hash and sum up the tree, then we'll end up at the same root hash and sum
value.
Before proofs are verified, the proof should first be decompressed:
<source lang="python">
decompress_merkle_proof(compressed_proof CompressedProof) -> []MerkleSumNode:
proof = []MerkleSumNode{}
for i in range(256):
if compressed_proof.bit_at(index=i) == 1:
proof.append(empty_hash_map[i])
else:
proof.append(compressed_proof.proof)
compressed_proof = drop_1(compressed_proof.proof)
return proof
</source>
With the proof decompressed, we verify the proof by hashing and summing up each
level.
<source lang="python">
verify_merkle_proof(proof []MerkleSumNode, root MerkleSumNode,
key [32]byte, value []byte, value_sum int64) -> bool:
for i in range(256):
if bit_index(i, key) == 0:
value = sha256(proof[-1-i], value, proof[1-i].sum, value_sum)
else:
value = sha256(value, proof[-1-i], value.sum, value_sum)
return root.hash == value && root.sum == value_sum
</source>
====Caching Optimizations====
TODO(roasbeef):
==Test Vectors==
Test vectors for Merkle Sum Sparse Merkle Trees can be found here:
* [[bip-tap-ms-smt/mssmt_tree_deletion.json|MS-SMT leaf deletion test vectors]]
* [[bip-tap-ms-smt/mssmt_tree_error_cases.json|Tree error test vectors]]
* [[bip-tap-ms-smt/mssmt_tree_proofs.json|MS-SMT proof test vectors]]
* [[bip-tap-ms-smt/mssmt_tree_replacement.json|MS-SMT leaf replacement test vectors]]
The test vectors are automatically generated by
[https://github.com/lightninglabs/taproot-assets/tree/main/mssmt unit tests in
the Taproot Assets GitHub repository].
==Backwards Compatibility==
==Reference Implementation==
github.com/lightninglabs/taproot-assets/tree/main/mssmt

View file

@ -0,0 +1,45 @@
{
"all_tree_leaves": [
{
"key": "0100000000000000000000000000000000000000000000000000000000000000",
"node": {
"value": "4f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c4",
"sum": "2775174756"
}
},
{
"key": "0200000000000000000000000000000000000000000000000000000000000000",
"node": {
"value": "7723b9faf9c51fd5d5788bb39d3c068fa6807d30f6201d3f6dfd31715d08b1733440cde1049608d23c4e45c5ed61f863350232f85827e7c292dc5f1eced1cbc912e3f5c420bd945911d3881ede5153d3b2cc85371fff98d2caf97cad6ef590014017f9690cab08989851",
"sum": "2977921451"
}
},
{
"key": "0400000000000000000000000000000000000000000000000000000000000000",
"node": {
"value": "79f8f54e3133fc2cdef259df2ba0d48f37bf9e43792e3a777214cf4aab6dde6deeb543a8813b71b5974136c1220d6218a252881f0f5677ff5b6aba127f19a5f3c5aac988543d7839a90a3f947c4e4d5c6ae1ab48dbd40456d1aa65339a4c15eb520e8ff9f965ac4c37735937cf09942e7958f8a6cddee41707423f715903ffe0d15af8c3140d3a736d23be7485fceb9f07c6509f2c506eda4ec9d30ccc133708f48d8828e332808c84a745d337296d871b9794de1c5d06534aaf65587526a84e2521f8b332645e0e72564bb308ecf99b7bc69608474389d1",
"sum": "3351083531"
}
}
],
"valid_test_cases": [
{
"root_hash": "c290ff98be50aa38892c07d61b41ff20e19b76d46cbe993d0c3e87411d0d1af6",
"root_sum": "2775174756",
"inserted_leaves": [
"0100000000000000000000000000000000000000000000000000000000000000",
"0200000000000000000000000000000000000000000000000000000000000000",
"0400000000000000000000000000000000000000000000000000000000000000"
],
"deleted_leaves": [
"0200000000000000000000000000000000000000000000000000000000000000",
"0400000000000000000000000000000000000000000000000000000000000000"
],
"replaced_leaves": null,
"inclusion_proofs": null,
"exclusion_proofs": null,
"comment": "sub tree deletion"
}
],
"error_test_cases": null
}

View file

@ -0,0 +1,42 @@
{
"all_tree_leaves": [
{
"key": "5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e9",
"node": {
"value": "52fdfc072182654f163f",
"sum": "1"
}
},
{
"key": "1e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784045d87f3",
"node": {
"value": "52fdfc072182654f163f",
"sum": "18446744073709551615"
}
}
],
"valid_test_cases": [
{
"root_hash": "3aef57ab466f3b8eebd90dc155816684553fc5f8888ffa95fe9944ee5a71c8ea",
"root_sum": "1",
"inserted_leaves": [
"5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e9"
],
"deleted_leaves": null,
"replaced_leaves": null,
"inclusion_proofs": null,
"exclusion_proofs": null,
"comment": "non overflowing leaf"
}
],
"error_test_cases": [
{
"inserted_leaves": [
"5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e9",
"1e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784045d87f3"
],
"error": "integer overflow",
"comment": "overflowing leaf"
}
]
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,324 @@
<pre>
BIP: ???
Layer: Applications
Title: Taproot Asset Flat File Proof Format
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
</pre>
==Abstract==
This document defines a flat file proof format as a standardized way to package
Taproot Asset proofs. The proof format itself is an append-only log of the prior
lineage of a given asset. Proofs are anchored at the initial "genesis output"
for a given asset. A proof of a single Taproot Asset state transition includes a
Bitcoin merkle proof, a Taproot Asset merkle-sum sparse merkle tree (MS-SMT)
inclusion proof, and finally a set of valid witnesses for the state transition.
==Copyright==
This document is licensed under the 2-clause BSD license.
==Motivation==
The Taproot Asset protocol is an overlay protocol that enables the
representation and transfer of assets on the base Bitcoin blockchain.
As Bitcoin is a UTXO-based system each asset is itself rooted at an initial
"genesis" transaction, which marks the creation of said asset.
An asset is therefore defined by its genesis output, as this marks its lineage.
To ensure implementations are able to verify provenance proofs across the
ecosystem, a standardized proof format is proposed. The proof format is a linear
log of state transitions, allowing new transfers/transition to simply be append
to the end of the fail.
==Design==
Proving provenance of an asset requires the following arguments at each point
in the past history of the asset:
* The very first snapshot of an asset is rooted at the genesis outpoint as dictated by the canonical Universe.
* A valid merkle proof that proves the inclusion of the genesis outpoint and resulting created asset.
* At each step/transition beyond the genesis outpoint:
** A valid merkle proof of a transaction which spends the outpoint referenced in the prior step.
** A valid MS-SMT opening proving the commitment of the new location of the asset.
** A valid asset witness state transition from the prior outpoint to the new location.
** A valid canonical Taproot Asset commitment exists for the given asset.
** If the transaction anchoring the state transition has other Taproot (P2TR) outputs, then a valid tapscript exclusion proof to prove that the commitment isn't duplicated elsewhere.
===Specification===
The Taproot Asset proof file is a flat file that records each relevant state
transition for a given asset to be verified. The file is verified incrementally,
with verification halting if an invalid state transition or proof is
encountered.
A file is a series of inclusion and state transition proofs rooted at a given
genesis outpoint. The very first transition requires no witness validation as
its the genesis outpoint.
====File Serialization====
A single inclusion and state transition proof has the following format is a TLV
blob with the following format:
* type: 0 (<code>version</code>)
** value:
*** [<code>uint32</code>:<code>version</code>]
* type: 1 (<code>prev_out</code>)
** value:
*** [<code>36*byte</code>:<code>txid || output_index</code>]
* type: 2 (<code>block_header</code>)
** value:
*** [<code>80*byte</code>:<code>bitcoin_header</code>]
* type: 3 (<code>anchor_tx</code>)
** value:
*** [<code>...*byte</code>:<code>serialized_bitcoin_tx</code>]
* type: 4 (<code>anchor_tx_merkle_proof</code>)
** value:
*** [<code>...*byte</code>:<code>merkle_inclusion_proof</code>]
* type: 5 (<code>taproot_asset_asset_leaf</code>)
** value:
*** [<code>tlv_blob</code>:<code>serialized_tlv_leaf</code>]
* type: 6 (<code>taproot_asset_inclusion_proofs</code>)
** value:
*** [<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
**** type: 0 (<code>output_index</code>
***** value: [<code>int32</code>:<code>index</code>]
**** type: 1 (<code>internal_key</code>
***** value: [<code>33*byte</code>:<code>y_parity_byte || schnorr_x_only_key</code>]
**** type: 2 (<code>taproot_asset_proof</code>)
***** value: [<code>...*byte</code>:<code>asset_proof</code>]
****** type: 0 (<code>taproot_asset_proof</code>)
******* value: [<code>...*byte</code>:<code>asset_inclusion_proof</code>]
******* type: 0
******** value: [<code>uint32</code>:<code>proof_version</code>]
******* type: 1
******** value: [<code>32*byte</code>:<code>asset_id</code>]
******* type: 2
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
****** type: 1 (<code>taproot_asset_inclusion_proof</code>)
******* value: [<code>...*byte</code>:<code>taproot_asset_inclusion_proof</code>]
******* type: 0
******** value: [<code>uint32</code>:<code>proof_version</code>]
******* type: 1
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
******* type: 2 (<code>taproot_sibling_preimage</code>)
******** value: [<code>byte</code>:<code>sibling_type</code>][<code>varint</code>:<code>num_bytes</code>][<code>...*byte</code>:<code>tapscript_preimage</code>]
**** type: 3 (<code>taproot_asset_commitment_exclusion_proof</code>
***** value: [<code>...*byte</code>:<code>taproot_exclusion_proof</code>]
****** type: 0 (<code>tap_image_1</code>)
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
****** type: 1 (<code>tap_image_2</code>)
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
****** type: 2 (<code>bip_86</code>)
******* value: [<code>byte 0x00/0x01</code>:<code>bip_86</code>]
* type: 7 (<code>taproot_exclusion_proofs</code>)
** value:
*** [<code>uint16</code>:<code>num_proofs</code>][<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
* type: 8 (<code>split_root_proof</code>)
** value:
*** [<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
* type: 9 (<code>meta_reveal</code>)
** value:
*** [<code>...*byte</code>:<code>asset_meta_reveal</code>]
**** type: 0 (<code>meta_type</code>
***** value: [<code>uint8</code>:<code>type</code>]
**** type: 1 (<code>meta_data</code>
***** value: [<code>*byte</code>:<code>meta_data_bytes</code>]
* type: 10 (<code>taproot_asset_input_splits</code>)
** value:
*** [<code>...*byte</code>:<code>nested_proof_map</code>]
* type: 11 (<code>challenge_witness</code>)
** value:
*** [<code>...*byte</code>:<code>challenge_witness</code>]
* type: 12 (<code>block_height</code>)
** value:
*** [<code>uint32</code>:<code>block_height</code>]
where:
* <code>version</code>: is the version of the single mint or transition proof, currently fixed to value <code>0</code>.
* <code>prev_out</code>: is the 36-byte outpoint of the Taproot Asset committed output being spent. If this is the very first proof, then this value will be the "genesis outpoint" for the given asset.
* <code>block_header</code>: is the 80-byte block header that includes a spend of the above outpoint.
* <code>merkle_inclusion_proof</code>: is the merkle inclusion proof of the transaction spending the <code>previous_outpoint</code>. This is serialized with a <code>BigSize</code> length prefix as:
** <code>proof_node_count || serialized_proof || proof_direction_bits</code>
** where:
*** <code>proof_node_count</code> is a <code>BigSize</code> integer specifying the number of nodes in the proof.
*** <code>serialized_proof</code> is <code>proof_node_count*32</code> bytes for the proof path.
*** <code>proof_direction_bits</code> is a bitfield of size <code>length_of_proof</code> with a value of <code>0</code> indicating a left direction, and <code>1</code> indicating a right direction.
* <code>anchor_tx</code>: is the transaction spending the <code>previous_outpoint</code>. This transaction commits to at least a single Taproot Asset tree within one of its outputs.
* <code>taproot_asset_taproot_proof</code>: is a nested TLV that can be used to prove either inclusion or a Taproot Asset, or the lack of a Taproot Asset commitment via the <code>taproot_asset_commitment_exclusion_proof</code>.
* <code>taproot_exclusion_proofs</code>: is a series of _exclusion_ proofs that prove that the other outputs in a transaction don't commit to a valid Taproot Asset. This re-uses the <code>taproot_asset_taproot_proof</code> structure, but will only contain an <code>taproot_asset_commitment_exclusion_proof</code> value and not also a <code>taproot_asset_taproot_proof</code> value.
* <code>split_root_proof</code>: is an optional <code>taproot_asset_taproot_proof</code> that proves the inclusion of the split commitment's root asset in case of an asset split.
* <code>taproot_asset_input_splits</code>: is an optional list of nested full proofs for any additional inputs found within the resulting asset.
* <code>asset_meta_reveal</code>: is an mandatory field (for genesis assets) that reveals the pre-image of the <code>asset_meta_hash</code> contained in the asset TLV.
** The <code>meta_type</code> field can be used to indicate how to parse/render the meta data pre-image.
*** The meta type currently defined are:
**** <code>0</code>: no true type, just designates an opaque data blob.
** The <code>meta_data</code> is the raw meta data itself.
*** If the contained asset is a genesis asset (has a valid genesis witness), then a verifier SHOULD verify that: `sha256(tlv_encode(meta_reveal)) == asset_meta_hash`.
*** This field MUST only be present for genesis asset proofs.
* <code>challenge_witness</code> is an optional asset witness over a well-defined asset state transition that proves ownership of the <code>script_key</code> the asset currently resides at.
* <code>block_height</code>: is the block height of the block that includes a spend of the <code>prev_out</code> outpoint.
The final flat proof file has the following format:
* [<code>u32</code>:<code>file_version</code>] version of proof file format, currently fixed to <code>0</code>.
* [<code>BigSize</code>:<code>num_proofs</code>] number of proofs contained in the file
* [<code>num_proof*proof</code>:<code>proofs</code>] encoded proofs
** [<code>BigSize</code>:<code>proof_len</code>] length of encoded proof
** [<code>proof_len*byte</code>:<code>proof_tlv_bytes</code>] a single proof encoded as a TLV stream as defined above
** [<code>32*byte</code>:<code>proof_checksum</code>] the checksum of the proof, which is <code>SHA256(prev_hash || proof_tlv_bytes)</code> where <code>prev_hash</code> is the checksum of the previous proof or a zero hash for the first proof.
====Proof Verification====
Verification of a proof file starts at the first entry (the genesis output
creation) and walks forward, validating each state transition and inclusion
proof in series. If any state transition is found to be invalid, then the asset
proof is invalid. Otherwise, if the file is consumed in full without any
violations, the proof is said to be valid.
Given a proof file for a given asset <code>f_proof</code>, genesis outpoint
<code>g</code> verification is defined as follows:
# Verify the integrity of the proof file:
## For each proof, extract the <code>proof_len</code>, <code>proof_len</code> number of bytes as <code>proof_tlv_bytes</code> and 32 bytes <code>proof_checksum</code>.
## Compute <code>SHA256(prev_hash || proof_tlv_bytes)</code> where <code>prev_hash</code> is the <code>proof_checksum</code> of the previous proof or a 32-byte zero hash for the first proof in a file.
## If this computed value doesn't match <code>proof_checksum</code>, verification fails.
# Verify each inclusion proof and state transition:
## Parse the next proof block from the flat file.
## If this is the first proof to be verified:
### Store the <code>previous_outpoint</code> as the genesis outpoint.
## Otherwise, verify that the <code>anchor_transaction</code> has an inputs that spends the ''prior'' <code>previous_outpoint</code>
## Given the <code>anchor_transaction</code> verify that the included <code>merkle_inclusion_proof</code> rooted at the merkle root of the <code>block_header</code> is valid.
## Parse the <code>tlv_proof_map</code>.
## If the <code>anchor_transaction</code> does not have ''at least'' <code>asset_output_pos</code> outputs, verification fails.
## Verify that the <code>asset_leaf_proof</code> embeds the <code>taproot_asset_leaf</code> at the outpout rooted at the <code>asset_output_pos</code> using the specified <code>internal_key</code> to compute the taproot commitment.
## Verify that the asset witness included at the <code>prev_asset_witness</code> field of the <code>taproot_asset_leaf</code> is valid based on the specific <code>asset_script_version</code>
## If a <code>split_commitment_opening</code> is present, verify that the included leaf is a valid opening rooted at the <code>taproot_asset_leaf</code>'s <code>split_commitment_root</code> field.
## If a <code>split_commitment_opening</code> is present, verify that an inclusion proof for the <code>split_commitment_root</code>'s leaf is present in <code>split_root_proof</code>.
## If the asset is a genesis asset, and the <code>asset_meta</code> field is present, then verify that <code>sha256(asset_meta) == asset.asset_meta_hash</code>
A pseudo-code routine for flat file verification follows:
<source lang="python">
verify_asset_file_proof(file_proof []byte, genesis_outpoint OutPoint,
assetID [32]byte) -> bool
genesis_outpoint, prev_outpoint = None
file_reader = new_bytes_reader(file_proof)
prev_hash = bytes(32)
while file_reader.len() != 0:
proof_block = parse_proof_block(file_reader)
sha_sum = sh256(prev_hash + proof_block.bytes())
if proof_block.proof_checksum != sha_sum:
return false
if genesis_outpoint is None:
genesis_outpoint = proof_block.previous_outpoint
txn = proof_block.txn
if genesis_outpoint is not None:
if !spends_prev_out(txn):
return false
if !verify_merkle_proof(
proof_block.block_header, proof_block.merkle_inclusion_proof, txn,
):
return false
proof_tlv_map = proof_block.tlv_map
if len(txn.outputs) < proof_tlv_map.asset_output_pos:
return false
if !verify_asset_tree_proof(
txn, proof_tlv_map.taproot_asset_leaf, proof_tlv_map.asset_leaf_proof,
):
return false
if !verify_taproot_asset_state_transition(proof_tlv_map.taproot_asset_leaf):
return false
if proof_tlv_map.challenge_witness is not None:
new_leaf = clone_unique_leaf(proof_tlv_map.taproot_asset_leaf)
new_leaf.script_key = NUMS_key
new_leaf.prev_witnesses = {{
prev_id: {
asset_id: proof_tlv_map.taproot_asset_leaf.asset_id
outpoint: 00000000...0000000:0
script_key: proof_tlv_map.taproot_asset_leaf.script_key
}
tx_witness: proof_tlv_map.challenge_witness
}}
if !verify_taproot_asset_state_transition(new_leaf):
return false
if proof_tlv_map.split_commitment_opening is not None:
if !verify_split_commitment(
proof_tlv_map.taproot_asset_leaf,
proof_tlv_map.split_commitment_opening,
):
return false
if !verify_asset_tree_proof(
txn,
proof_tlv_map.split_commitment_opening.split_commitment_root,
proof_tlv_map.split_root_proof,
):
return false
has_meta_reveal = proof_tlv_map.meta_reveal is not None
has_meta_hash = proof_tlv_map.asset.meta_hash is not None
is_genesis_asset = is_genesis_asset(proof_tlv_map.asset)
match:
case has_meta_reveal && !is_genesis_asset:
return false
case has_meta_reveal && is_genesis_asset:
meta_hash := sha256(meta_reveal)
if meta_hash != proof_tlv_map.asset.meta_hash:
return false
case has_meta_hash && is_genesis_asset && !has_meta_reveal:
return false
case !has_meta_reveal && is_genesis_asset:
return false
return true
</source>
=====Ownership proof=====
An optional ownership proof can be added to a proof through the
<code>challenge_witness</code> field. That witness must be a valid asset
<code>tx_witness</code> over a well-defined asset state transition that spends
the full amount of the asset to the NUMS key.
The state transition can be created with the following steps:
# Create a deep copy of the asset to prove ownership of.
# Truncate the <code>prev_witnesses</code> list to just a single element.
# Set the <code>prev_witnesses[0].prev_id.out_point</code> to the empty outpoint (all zero hash and zero index).
# Set the <code>prev_witnesses[0].prev_id.script_key</code> to the asset's script key.
# Set the asset's <code>script_key</code> to the NUMS key.
# Create a signature for the asset state transition, using the interactive flow (no split tomb stone).
# Extract just the <code>prev_witnesses[0].tx_witness</code> from the signed state transition and append that to the proof as the <code>challenge_witness</code>.
==Test Vectors==
Test vectors for the [[File Serialization]] can be found here:
* [[bip-tap-proof-file/proof_tlv_encoding_generated.json|Proof TLV encoding test vectors]]
* [[bip-tap-proof-file/proof_tlv_encoding_error_cases.json|Proof TLV encoding error test vectors]]
* [[bip-tap-proof-file/proof_tlv_encoding_regtest.json|Fully valid regtest proof TLV encoding test vectors]]
Some of the test vectors are automatically generated by
[https://github.com/lightninglabs/taproot-assets/tree/main/proof unit tests in
the Taproot Assets GitHub repository].
==Backwards Compatibility==
==Reference Implementation==
github.com/lightninglabs/taproot-assets/tree/main/proof

View file

@ -0,0 +1,3 @@
{
"error_test_cases": null
}

View file

@ -0,0 +1,603 @@
{
"valid_test_cases": [
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "f573ed549022595804d8f1151569af45124301c7dc7c8fdf2435b51834176322",
"timestamp": 1473417797,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120e8bee22dd320d51864e8499a73d374739a0fce94b3eb10c5624ba2159a1c4cdb00000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "8d73ec3f2525632186845c95d4491d1b3a768b7c4e0b6804951aa42655d9b95f:2092150027",
"genesis_tag": "eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f1",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 379326753,
"genesis_type": 1,
"amount": 1,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "0250fb435f8fc76fc75736ac89956406e882a468e929da69ca596a716ebcfa8516",
"group_key": {
"group_key": "02f51bdc1380b8021dca065edf24ee521a4d6d5ceba51abb7877df544e93acc319",
"group_key_sig": "e19478adf14eba5767df3badbd3c6cfa8593a561acd626cb12cae73f8aad4a0b0d1af7a56ac3085991fb5a1b41d699f0fd63a2bea5bfdcef378e5f37c0e0cb0d"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "024a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "af542dec7585eaac495164faeb9c68ebc8b4d8e571a553d6732006063466b65d"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000002263173418b53524df8f7cdcc701431245af691515f1d8045859229054ed73f54592d2570000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120e8bee22dd320d51864e8499a73d374739a0fce94b3eb10c5624ba2159a1c4cdb0000000003010004fd018a000100018a5fb9d95526a41a9504680b4e7c8b763a1b1d49d4955c8486216325253fec738d7cb3ad0b40656239643138613434373834303435643837663363363763663232373436653939356166356132353336373935316261613266663663643437316334383366310000000000000000000000000000000000000000000000000000000000000000169c11210102010103010106690167006500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000802000009210250fb435f8fc76fc75736ac89956406e882a468e929da69ca596a716ebcfa85160a6102f51bdc1380b8021dca065edf24ee521a4d6d5ceba51abb7877df544e93acc319e19478adf14eba5767df3badbd3c6cfa8593a561acd626cb12cae73f8aad4a0b0d1af7a56ac3085991fb5a1b41d699f0fd63a2bea5bfdcef378e5f37c0e0cb0d059f0004000000000121024a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3027400490001000120af542dec7585eaac495164faeb9c68ebc8b4d8e571a553d6732006063466b65d02220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b0400000001",
"comment": "collectible genesis"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "6a45e1c2a5f0bde4001a718be7f637e62e5bdd10e0dc3742356fb57370290393",
"timestamp": 424111158,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120f6299f81fa3ed727d60250c19885a9e03576c506dd58d4c0f55764670beea68900000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "3f71f8cb984b92f67403049442fd5ad145f49143f7f4a5ee3b22b02936d4ff9b:4165004363",
"genesis_tag": "bb358b0c3b525da1786f9fff094279db1944ebd7a19d0f7bbacbe0255aa5b7d4",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 2432798076,
"genesis_type": 1,
"amount": 1,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02661e637f64d8d63f45a25890073502387b18f3f8aa7fd7704348f35ced5423fa",
"group_key": {
"group_key": "02475ad4761032ee378dff99a4bf0d1f63636d5f0e4df935ba0f117af249628e8c",
"group_key_sig": "cd4f5a65a7900c1096f9c994be4ea60eedc281cfd0d00e9260f2fcf9e5dfbd210c0cec330a3d0bd7ed33cee289eb7513ad53c065ab78ee15cca60388c164e215"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02af086d6428c5621941450bbefec061b5056d8706d659f9eebd7043400a4c0f93",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "af9b4888e4061d2fc1980cc7e3eac3f144dd99602b76a159605147a3180a0393"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": "00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd88"
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000009303297073b56f354237dce010dd5b2ee637f6e78b711a00e4bdf0a5c2e1456a366c47190000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120f6299f81fa3ed727d60250c19885a9e03576c506dd58d4c0f55764670beea6890000000003010004fd018a000100018a9bffd43629b0223beea5f4f74391f445d15afd4294040374f6924b98cbf8713ff840ec4b4062623335386230633362353235646131373836663966666630393432373964623139343465626437613139643066376262616362653032353561613562376434000000000000000000000000000000000000000000000000000000000000000091018d7c01020101030101066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102661e637f64d8d63f45a25890073502387b18f3f8aa7fd7704348f35ced5423fa0a6102475ad4761032ee378dff99a4bf0d1f63636d5f0e4df935ba0f117af249628e8ccd4f5a65a7900c1096f9c994be4ea60eedc281cfd0d00e9260f2fcf9e5dfbd210c0cec330a3d0bd7ed33cee289eb7513ad53c065ab78ee15cca60388c164e21505bc000400000000012102af086d6428c5621941450bbefec061b5056d8706d659f9eebd7043400a4c0f93029100490001000120af9b4888e4061d2fc1980cc7e3eac3f144dd99602b76a159605147a3180a039302220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff021b00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd880b0400000001",
"comment": "collectible with leaf preimage"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "90c284d06f3a4d9e08ec96d7f8702e31d4953a8d65171227abac030a78a93bed",
"timestamp": 2783629501,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120c67a67da813c602d8824a449b2f404c0f35b255bc874852918a3fe072a16a0a300000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "e81ede4561ad67830356aa6b86dff7ab244fcd36e9f7676678e7aa73fac82541:3738690577",
"genesis_tag": "c6077dbb5722f5717a289a266f97647981998ebea89c0b4b373970115e82ed6f",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 1050259624,
"genesis_type": 1,
"amount": 1,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02bc9c371fa4e83557a1844db0a9e636dea420ebc1620a9b6cd499557bb20f5b3e",
"group_key": {
"group_key": "032964eeba96725a8373fa55867fe0a6d01994d9c8822d8a76ac00181b65b1dd9a",
"group_key_sig": "4d07c09a05b7de04956f4f175f3fa6b35249f15619b4a5b4d14b812b7dd1d5e6b0684779937a9762de3f7e30cc95ebdc044d930741dba74b31d3ddc64cef98b8"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "021af16655f63c4b9f95b5961ad1c97ef0e8fa7f9218801870e5b2252a6427db8d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "9d6d650760287dd9a16d719df2303da025dfb675f02a3c5ea525664831646214"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": "016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af43"
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000ed3ba9780a03acab271217658d3a95d4312e70f8d796ec089e4d3a6fd084c290bdd0eaa50000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120c67a67da813c602d8824a449b2f404c0f35b255bc874852918a3fe072a16a0a30000000003010004fd018a000100018a4125c8fa73aae7786667f7e936cd4f24abf7df866baa56038367ad6145de1ee8ded7e411406336303737646262353732326635373137613238396132363666393736343739383139393865626561383963306234623337333937303131356538326564366600000000000000000000000000000000000000000000000000000000000000003e99b0a801020101030101066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102bc9c371fa4e83557a1844db0a9e636dea420ebc1620a9b6cd499557bb20f5b3e0a61032964eeba96725a8373fa55867fe0a6d01994d9c8822d8a76ac00181b65b1dd9a4d07c09a05b7de04956f4f175f3fa6b35249f15619b4a5b4d14b812b7dd1d5e6b0684779937a9762de3f7e30cc95ebdc044d930741dba74b31d3ddc64cef98b805e20004000000000121021af16655f63c4b9f95b5961ad1c97ef0e8fa7f9218801870e5b2252a6427db8d02b7004900010001209d6d650760287dd9a16d719df2303da025dfb675f02a3c5ea52566483164621402220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0241016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af430b0400000001",
"comment": "collectible with branch preimage"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "b1b29433dad76a64f5c3c15f01b6eed67e1511ac310f892662ccea236a5075c0",
"timestamp": 3929885861,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120fa90a787c9b095646058b3b6c1bdc44753309c94ea8fe446fedca3cbe891e78800000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "2db92d0169a39144afd37941439089bed31f1cb9e6c6a03cb44af864ba29ee07:737360203",
"genesis_tag": "a665f606f6a63b7f3dfd2567c18979e4d60f26686d9bf2fb26c901ff354cde16",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 1108760575,
"genesis_type": 0,
"amount": 5000,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02610f4ad4f6fcb2f75b10b9674cfc140dd97921b53a2f5db4b7f807a5a87d2187",
"group_key": {
"group_key": "02f2a1617673e0d62a2dfe09f6a7faa670f170256288cfabe4ff98dd993f988a5e",
"group_key_sig": "fa3c720b7dc7483f4a33023407490387f752b117f9d9fec5fdb76cfcadcc2ce5ce98d093b6d5e474835cd8191461ce7b6472c5a38ce6c041a6e8676b585894f5"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02f7fd86c602d2ac12d72a7ee0422749b1bfe555c0ee8f24f5ea885a39e36f8cf9",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "a0319d51ea16813396aed95d9a89abbd4478d3ce39b41ac0c1a086dfe89c5fef"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000c075506a23eacc6226890f31ac11157ed6eeb6015fc1c3f5646ad7da3394b2b1a54c3dea0000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120fa90a787c9b095646058b3b6c1bdc44753309c94ea8fe446fedca3cbe891e7880000000003010004fd018c000100018a07ee29ba64f84ab43ca0c6e6b91c1fd3be8990434179d3af4491a369012db92d2bf3394b40613636356636303666366136336237663364666432353637633138393739653464363066323636383664396266326662323663393031666633353463646531360000000000000000000000000000000000000000000000000000000000000000421657ff000201000303fd1388066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102610f4ad4f6fcb2f75b10b9674cfc140dd97921b53a2f5db4b7f807a5a87d21870a6102f2a1617673e0d62a2dfe09f6a7faa670f170256288cfabe4ff98dd993f988a5efa3c720b7dc7483f4a33023407490387f752b117f9d9fec5fdb76cfcadcc2ce5ce98d093b6d5e474835cd8191461ce7b6472c5a38ce6c041a6e8676b585894f5059f000400000000012102f7fd86c602d2ac12d72a7ee0422749b1bfe555c0ee8f24f5ea885a39e36f8cf9027400490001000120a0319d51ea16813396aed95d9a89abbd4478d3ce39b41ac0c1a086dfe89c5fef02220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b0400000001",
"comment": "normal genesis"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "dfe3487fad14f5dacca8e1a1f5652210df638b0639d252228491be1c1a700f65",
"timestamp": 1729403804,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120bca2d7e7dd677df0ce9b9c1cea124c674ead284bf60dadd8ed967d47685d396e00000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "41e52ad269fd8e5f04756b36dbc9b344e9031d27b8b352f7ab3641fe3dea7902:2817351063",
"genesis_tag": "17e924aef78ae151c00755925836b7075885650c30ec29a3703934bf50a28da1",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 647263805,
"genesis_type": 0,
"amount": 5000,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "029e47e906bfa2ee6cbba2c920b6f80d679928c40fe0c147d33c68cc5543f14637",
"group_key": {
"group_key": "030785de067c85d0cd3d27a4fdebe7394c1d18520a4303a415d3ba00f9429b2ef3",
"group_key_sig": "4f70f482651e959550cc897a94dea65d7ffacfa6d0842fa4de9b5bf9b5fee60e0ac3cdc60a9a22627af9c3ee6d6397eaced206bf3f6473f623b6ea44bbc96206"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02f820ac404967c0e36fcd7a0d6d8e8a3150801f18947c2299a2e024bf8aa25341",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "7440c1f12cf25120108c1b827e62ccfcde709a664cb3fb8396ab70aa18546f8a"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": "00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd88"
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000650f701a1cbe91842252d239068b63df102265f5a1e1a8ccdaf514ad7f48e3df9c9b14670000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120bca2d7e7dd677df0ce9b9c1cea124c674ead284bf60dadd8ed967d47685d396e0000000003010004fd018c000100018a0279ea3dfe4136abf752b3b8271d03e944b3c9db366b75045f8efd69d22ae541a7ed5d97403137653932346165663738616531353163303037353539323538333662373037353838353635306333306563323961333730333933346266353061323864613100000000000000000000000000000000000000000000000000000000000000002694763d000201000303fd13880669016700650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080200000921029e47e906bfa2ee6cbba2c920b6f80d679928c40fe0c147d33c68cc5543f146370a61030785de067c85d0cd3d27a4fdebe7394c1d18520a4303a415d3ba00f9429b2ef34f70f482651e959550cc897a94dea65d7ffacfa6d0842fa4de9b5bf9b5fee60e0ac3cdc60a9a22627af9c3ee6d6397eaced206bf3f6473f623b6ea44bbc9620605bc000400000000012102f820ac404967c0e36fcd7a0d6d8e8a3150801f18947c2299a2e024bf8aa253410291004900010001207440c1f12cf25120108c1b827e62ccfcde709a664cb3fb8396ab70aa18546f8a02220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff021b00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd880b0400000001",
"comment": "normal with leaf preimage"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "cff9e231e7cffb62784ce3cfb8def691c3d7529fe94205f6e32baf8466e9e616",
"timestamp": 1018572551,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251208f18ebe5a34e6fd58693a21a3b7357b25f17f16ce85f1ce4ef48981bb4d73f9b00000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "d6090ec04ff5f26283efc6c6443faf8eb3e4a15ca80d72521a90ae3e3e4a3056:210616852",
"genesis_tag": "01a239c4365854c3af7f6b41d631f92b9a8d12f41257325fff332f7576b06205",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 3243509860,
"genesis_type": 0,
"amount": 5000,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02ca32de61e7923279664dc4d609b8e68cd88fcd096bcfc5fcbd9d5e20ed14f455",
"group_key": {
"group_key": "03f072d865cd42fbd6290c62c0a7067a403c9557fb998bd9736ceea5a774b974af",
"group_key_sig": "1924b5e819e5e26eed905d14d39898aed2d9dcab3f91d80a94a272756164ae634177042d85c8a7593613771ce1d981a8d88af6b209c77daefb6e0fbac0137377"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02210ce45fef3bc702f0878323249c0263e0288217f9374a3661ec361d5261474f",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "f15e3049ab9c051ddf9d5e5cba119339708418231d3ce06789174e4e3c682271"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": "016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af43"
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000016e6e96684af2be3f60542e99f52d7c391f6deb8cfe34c7862fbcfe731e2f9cf072fb63c0000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251208f18ebe5a34e6fd58693a21a3b7357b25f17f16ce85f1ce4ef48981bb4d73f9b0000000003010004fd018c000100018a56304a3e3eae901a52720da85ca1e4b38eaf3f44c6c6ef8362f2f54fc00e09d60c8dc21440303161323339633433363538353463336166376636623431643633316639326239613864313266343132353733323566666633333266373537366230363230350000000000000000000000000000000000000000000000000000000000000000c1540864000201000303fd1388066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102ca32de61e7923279664dc4d609b8e68cd88fcd096bcfc5fcbd9d5e20ed14f4550a6103f072d865cd42fbd6290c62c0a7067a403c9557fb998bd9736ceea5a774b974af1924b5e819e5e26eed905d14d39898aed2d9dcab3f91d80a94a272756164ae634177042d85c8a7593613771ce1d981a8d88af6b209c77daefb6e0fbac013737705e2000400000000012102210ce45fef3bc702f0878323249c0263e0288217f9374a3661ec361d5261474f02b700490001000120f15e3049ab9c051ddf9d5e5cba119339708418231d3ce06789174e4e3c68227102220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0241016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af430b0400000001",
"comment": "normal with branch preimage"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "50407cde9e5f0cf21ae351f4997d3cc3122f9a93e3c3a16f5269c619ec1211c3",
"timestamp": 3691164560,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251200874649b4e0e0f15fd5e47d337a19eead0e4ad7fd2ec8a6bdbd5c20d6c60329600000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "70e7ac7417bf383423cfcde2c269398e40b01aa47d7fbfbcafd915bb5ce263e2:1058894887",
"genesis_tag": "6710a7960732ca52cf53c3f520c889b79bf504cfb57c7601232d589baccea9d6",
"genesis_meta_hash": "a34a4bd8a261e96320dcd1e43f134b84f3421a5433336724de1aa5d07cef6d13",
"genesis_output_index": 503926682,
"genesis_type": 0,
"amount": 5000,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "024236a05cff1fc479f8a2abc0fb95874b4e416bb9f4e617e85a8ea8b492189a56",
"group_key": {
"group_key": "02b6f3ea9dbc2aec162b5c5461fde8e000e8ce33e75e71e9053edb4564dea457cd",
"group_key_sig": "ddb89159dd50a9ca6794aec56895a26e7b4b9c92e1d96158cc49de9d87051adc904de5b3ddbe9c2f5f959cf142b2b3c5ef92f73269a062de75b8d6bf0b4b7309"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02a1581b958162db9a2ab8b13079694ab91ea08ba74e99635af948e7141dcdcdfe",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "3e3ac273be361ad0f51e35fe02af232e01de9043d7d701594387c556877ac537"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": {
"type": 0,
"data": "6d65616e7420696e2063726f6b696e67206e657665726d6f7265"
},
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000c31112ec19c669526fa1c3e3939a2f12c33c7d99f451e31af20c5f9ede7c405090b302dc0000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251200874649b4e0e0f15fd5e47d337a19eead0e4ad7fd2ec8a6bdbd5c20d6c6032960000000003010004fd018c000100018ae263e25cbb15d9afbcbf7f7da41ab0408e3969c2e2cdcf233438bf1774ace7703f1d74274036373130613739363037333263613532636635336333663532306338383962373962663530346366623537633736303132333264353839626163636561396436a34a4bd8a261e96320dcd1e43f134b84f3421a5433336724de1aa5d07cef6d131e094f9a000201000303fd13880669016700650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080200000921024236a05cff1fc479f8a2abc0fb95874b4e416bb9f4e617e85a8ea8b492189a560a6102b6f3ea9dbc2aec162b5c5461fde8e000e8ce33e75e71e9053edb4564dea457cdddb89159dd50a9ca6794aec56895a26e7b4b9c92e1d96158cc49de9d87051adc904de5b3ddbe9c2f5f959cf142b2b3c5ef92f73269a062de75b8d6bf0b4b7309059f000400000000012102a1581b958162db9a2ab8b13079694ab91ea08ba74e99635af948e7141dcdcdfe0274004900010001203e3ac273be361ad0f51e35fe02af232e01de9043d7d701594387c556877ac53702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff081f000100011a6d65616e7420696e2063726f6b696e67206e657665726d6f72650b0400000001",
"comment": "normal asset with a meta reveal"
},
{
"proof": {
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"block_header": {
"version": 0,
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"merkle_root": "632d8d2fc327b4d5453769145b341a0b3111872b481a92e303fc6a91680bf45f",
"timestamp": 1084726331,
"bits": 0,
"nonce": 0
},
"block_height": 1,
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a0100000000000022512094f2a868ad1f3bee9f11e8fa309fba5eb4f9ec4964c4eefa9325b18ca0a3c80d00000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "0cb058bd10f13e41b7c09a3e6f241c576f9ac7070f0914c3f10e0f21255197d7:1325329117",
"genesis_tag": "8f8921a266b11d0f334c62fe52ba53af19779cb2948b6570ffa0b773963c130a",
"genesis_meta_hash": "691a588e330c10a4ec7261f0b571486a8223f13fd7594e60eee6ce8013bf232f",
"genesis_output_index": 4105630847,
"genesis_type": 1,
"amount": 1,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "020aca705bbfdaea0fdaa052837c3801953a2642ca7009a99fe2884cb616bce3a5",
"group_key": {
"group_key": "02c59d39e7c47626d9b9153495b5ce750716818a19938d2730692ed8bbafce5f21",
"group_key_sig": "52d12e017cd2430e08d272ec76baea5aaac6960c72f5487e683034dfae35ce0d4301c573e13e1fd0d700c3349dc0a93ffb0867be04f862a6dd7962e1eb567628"
}
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "0265c2da862edf7e730c69c5f1677ce0104a81adda912cc97f54a7aeec9e1b0943",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "99539548cd53af1920671ef2c07d9078ad6ffd2646563197fecb125a687f9548"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": null,
"split_root_proof": null,
"meta_reveal": {
"type": 0,
"data": "7368616c6c206265206c6966746564206e657665726d6f7265"
},
"additional_inputs": null,
"challenge_witness": null
},
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000005ff40b68916afc03e3921a482b8711310b1a345b14693745d5b427c32f8d2d633b9ca7400000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a0100000000000022512094f2a868ad1f3bee9f11e8fa309fba5eb4f9ec4964c4eefa9325b18ca0a3c80d0000000003010004fd018a000100018ad7975125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd58b00c4efeeadd4038663839323161323636623131643066333334633632666535326261353361663139373739636232393438623635373066666130623737333936336331333061691a588e330c10a4ec7261f0b571486a8223f13fd7594e60eee6ce8013bf232ff4b6f47f010201010301010669016700650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080200000921020aca705bbfdaea0fdaa052837c3801953a2642ca7009a99fe2884cb616bce3a50a6102c59d39e7c47626d9b9153495b5ce750716818a19938d2730692ed8bbafce5f2152d12e017cd2430e08d272ec76baea5aaac6960c72f5487e683034dfae35ce0d4301c573e13e1fd0d700c3349dc0a93ffb0867be04f862a6dd7962e1eb567628059f00040000000001210265c2da862edf7e730c69c5f1677ce0104a81adda912cc97f54a7aeec9e1b094302740049000100012099539548cd53af1920671ef2c07d9078ad6ffd2646563197fecb125a687f954802220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff081e00010001197368616c6c206265206c6966746564206e657665726d6f72650b0400000001",
"comment": "collectible with a meta reveal"
}
],
"error_test_cases": null
}

View file

@ -0,0 +1,911 @@
{
"valid_test_cases": [
{
"proof": {
"prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"block_header": {
"version": 541065216,
"prev_block": "44d3b42cf499c0e5c7ce75cb2b9d293b161361101620108c873d4e90772221e6",
"merkle_root": "e3a640f85a22dcf6082c8279aacae8bcbf58183b50e75efc05a844a88dbcff79",
"timestamp": 1693480105,
"bits": 545259519,
"nonce": 0
},
"block_height": 441,
"anchor_tx": "02000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000",
"tx_merkle_proof": {
"nodes": [
"18791a381a48962338b8f5b0b882adee702b3b13c8a76127aaca77b169ac08dd"
],
"bits": [
false
]
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 1500,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93",
"group_key": null
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 1,
"internal_key": "024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": null,
"meta_reveal": {
"type": 0,
"data": "69746573742d6d65746164617461"
},
"additional_inputs": null,
"challenge_witness": null
},
"expected": "0024005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a00000000015000004020e6212277904e3d878c102016106113163b299d2bcb75cec7e5c099f42cb4d34479ffbc8da844a805fc5ee7503b1858bfbce8caaa79822c08f6dc225af840a6e3a974f064ffff7f200000000002f702000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000032201dd08ac69b177caaa2761a7c8133b2b70eead82b8b0f5b8382396481a381a79180004f80001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd05dc066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9305c7000400000000012102fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0630012e0004000000010121024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da03030201010813000100010e69746573742d6d657461646174610b04000001b9",
"comment": "valid regtest genesis proof with meta reveal"
},
{
"proof": {
"prev_out": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
"block_header": {
"version": 0,
"prev_block": "0000000000000000000000000000000000000000000000000000000000000000",
"merkle_root": "0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": 2288912640,
"bits": 0,
"nonce": 0
},
"block_height": 0,
"anchor_tx": "0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa2974900000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 300,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93"
},
"tx_witness": [
"a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda"
],
"split_commitment": null
}
],
"split_commitment_root": {
"hash": "c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb626269",
"sum": "1500"
},
"script_version": 0,
"script_key": "02bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff",
"group_key": null
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 1,
"internal_key": "0210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0001ca33245063350720fab0d245ba29b6d7ac15548847358e986986f435c5c9cef900000000000004b0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
{
"output_index": 2,
"internal_key": "02fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": null,
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "002475bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000000150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000096e88000000000000000002fd018d0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa297490000000003010004fd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd012c06ad01ab006575bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000002fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9301420140a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda0728c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb62626900000000000005dc08020000092102bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff05c70004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf06f802c700040000000101210210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8029c007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a0001ca33245063350720fab0d245ba29b6d7ac15548847358e986986f435c5c9cef900000000000004b0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed03030201010b0400000000",
"comment": "valid regtest proof for split root"
},
{
"proof": {
"prev_out": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
"block_header": {
"version": 0,
"prev_block": "0000000000000000000000000000000000000000000000000000000000000000",
"merkle_root": "0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": 2288912640,
"bits": 0,
"nonce": 0
},
"block_height": 0,
"anchor_tx": "0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa2974900000000",
"tx_merkle_proof": {
"nodes": [],
"bits": []
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 1200,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": {
"proof": "00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"root_asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 300,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93"
},
"tx_witness": [
"a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda"
],
"split_commitment": null
}
],
"split_commitment_root": {
"hash": "c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb626269",
"sum": "1500"
},
"script_version": 0,
"script_key": "02bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff",
"group_key": null
}
}
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3",
"group_key": null
},
"inclusion_proof": {
"output_index": 1,
"internal_key": "0210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 0,
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
{
"output_index": 2,
"internal_key": "02fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": {
"output_index": 0,
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "002475bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000000150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000096e88000000000000000002fd018d0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa297490000000003010004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd04b006fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd012c06ad01ab006575bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000002fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9301420140a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda0728c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb62626900000000000005dc08020000092102bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff08020000092102a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3059f00040000000101210210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe80274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06fd012002ef0004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c02c4007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf2e000400000002012102fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed030302010107c70004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0b0400000000",
"comment": "valid regtest split proof"
},
{
"proof": {
"prev_out": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
"block_header": {
"version": 541065216,
"prev_block": "6f4a14b01002d14c538065d2f9264c224231c995c7e96929bc350b28364fefcc",
"merkle_root": "1ad4f663df73cb525aea66ee5c4e7298c721feeabb5f139b270be353363b16d0",
"timestamp": 1693480105,
"bits": 545259519,
"nonce": 2
},
"block_height": 444,
"anchor_tx": "0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000",
"tx_merkle_proof": {
"nodes": [
"acdaf9ef85967c188235d6048f6c0fef91bedf570c199f3c9d9cbd27f7294aed"
],
"bits": [
false
]
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 500,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": {
"proof": "0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"root_asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 700,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3"
},
"tx_witness": [
"731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a87142715"
],
"split_commitment": null
}
],
"split_commitment_root": {
"hash": "5276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a627",
"sum": "1200"
},
"script_version": 0,
"script_key": "02e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e",
"group_key": null
}
}
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16",
"group_key": null
},
"inclusion_proof": {
"output_index": 1,
"internal_key": "024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b7",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 0,
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
{
"output_index": 2,
"internal_key": "02a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b123",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": {
"output_index": 0,
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": [
"bbb66f7d3cd53b00143cf01fd9f71b65f1c93e2074c18ebe4e290c24e4c3cbdb81d66b568b498f4f9b10759684a0f5d43761c17421ec0b9c163e73e217f9eec3"
]
},
"expected": "0024ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a300000001015000004020ccef4f36280b35bc2969e9c795c93142224c26f9d26580534cd10210b0144a6fd0163b3653e30b279b135fbbeafe21c798724e5cee66ea5a52cb73df63f6d41aa974f064ffff7f200200000002fd018c0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000032201ed4a29f727bd9c9d3c9f190c57dfbe91ef0f6c8f04d63582187c9685eff9daac0004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd01f406fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd02bc06ad01ab0065ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a3000000012fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef301420140731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a8714271507285276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a62700000000000004b008020000092102e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e08020000092102dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16059f0004000000010121024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b70274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06f802c7000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d029c007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b1230303020101079f000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d0274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a420140bbb66f7d3cd53b00143cf01fd9f71b65f1c93e2074c18ebe4e290c24e4c3cbdb81d66b568b498f4f9b10759684a0f5d43761c17421ec0b9c163e73e217f9eec30b04000001bc",
"comment": "valid regtest ownership proof"
},
{
"proof": {
"prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"block_header": {
"version": 541065216,
"prev_block": "44d3b42cf499c0e5c7ce75cb2b9d293b161361101620108c873d4e90772221e6",
"merkle_root": "e3a640f85a22dcf6082c8279aacae8bcbf58183b50e75efc05a844a88dbcff79",
"timestamp": 1693480105,
"bits": 545259519,
"nonce": 0
},
"block_height": 441,
"anchor_tx": "02000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000",
"tx_merkle_proof": {
"nodes": [
"18791a381a48962338b8f5b0b882adee702b3b13c8a76127aaca77b169ac08dd"
],
"bits": [
false
]
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 1500,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93",
"group_key": null
},
"inclusion_proof": {
"output_index": 0,
"internal_key": "02fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 1,
"internal_key": "024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": null,
"meta_reveal": {
"type": 0,
"data": "69746573742d6d65746164617461"
},
"additional_inputs": null,
"challenge_witness": null
},
"expected": "0024005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a00000000015000004020e6212277904e3d878c102016106113163b299d2bcb75cec7e5c099f42cb4d34479ffbc8da844a805fc5ee7503b1858bfbce8caaa79822c08f6dc225af840a6e3a974f064ffff7f200000000002f702000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000032201dd08ac69b177caaa2761a7c8133b2b70eead82b8b0f5b8382396481a381a79180004f80001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd05dc066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9305c7000400000000012102fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0630012e0004000000010121024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da03030201010813000100010e69746573742d6d657461646174610b04000001b9",
"comment": "valid regtest proof file index 0"
},
{
"proof": {
"prev_out": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
"block_header": {
"version": 541065216,
"prev_block": "1f69c24c7fdfe348927099ebc9465b6bc76f26684079fe5cbb80762d817aa62e",
"merkle_root": "fc22bfd5edea2d6ecaa858e7170e61c7ba52d0bdb02a3a10d78319dd93d51bae",
"timestamp": 1693480105,
"bits": 545259519,
"nonce": 1
},
"block_height": 442,
"anchor_tx": "0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa2974900000000",
"tx_merkle_proof": {
"nodes": [
"f4deee6295b812281f0277d9e1b3f3d8c4d8b5634bc91cd10c4d02942f23261e"
],
"bits": [
false
]
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 1200,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": {
"proof": "00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"root_asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 300,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93"
},
"tx_witness": [
"a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda"
],
"split_commitment": null
}
],
"split_commitment_root": {
"hash": "c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb626269",
"sum": "1500"
},
"script_version": 0,
"script_key": "02bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff",
"group_key": null
}
}
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3",
"group_key": null
},
"inclusion_proof": {
"output_index": 1,
"internal_key": "0210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 0,
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
{
"output_index": 2,
"internal_key": "02fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": {
"output_index": 0,
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "002475bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000000150000040202ea67a812d7680bb5cfe794068266fc76b5b46c9eb99709248e3df7f4cc2691fae1bd593dd1983d7103a2ab0bdd052bac7610e17e758a8ca6e2deaedd5bf22fca974f064ffff7f200100000002fd018d0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa29749000000000322011e26232f94024d0cd11cc94b63b5d8c4d8f3b3e1d977021f2812b89562eedef40004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd04b006fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd012c06ad01ab006575bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000002fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9301420140a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda0728c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb62626900000000000005dc08020000092102bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff08020000092102a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3059f00040000000101210210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe80274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06fd012002ef0004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c02c4007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf2e000400000002012102fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed030302010107c70004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0b04000001ba",
"comment": "valid regtest proof file index 1"
},
{
"proof": {
"prev_out": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
"block_header": {
"version": 541065216,
"prev_block": "6f4a14b01002d14c538065d2f9264c224231c995c7e96929bc350b28364fefcc",
"merkle_root": "1ad4f663df73cb525aea66ee5c4e7298c721feeabb5f139b270be353363b16d0",
"timestamp": 1693480105,
"bits": 545259519,
"nonce": 2
},
"block_height": 444,
"anchor_tx": "0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000",
"tx_merkle_proof": {
"nodes": [
"acdaf9ef85967c188235d6048f6c0fef91bedf570c199f3c9d9cbd27f7294aed"
],
"bits": [
false
]
},
"asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 500,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": {
"proof": "0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"root_asset": {
"version": 0,
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
"genesis_tag": "first-itestbuxx",
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 700,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3"
},
"tx_witness": [
"731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a87142715"
],
"split_commitment": null
}
],
"split_commitment_root": {
"hash": "5276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a627",
"sum": "1200"
},
"script_version": 0,
"script_key": "02e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e",
"group_key": null
}
}
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16",
"group_key": null
},
"inclusion_proof": {
"output_index": 1,
"internal_key": "024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b7",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"exclusion_proofs": [
{
"output_index": 0,
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
{
"output_index": 2,
"internal_key": "02a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b123",
"commitment_proof": null,
"tapscript_proof": {
"tap_preimage_1": "",
"tap_preimage_2": "",
"bip86": true
}
}
],
"split_root_proof": {
"output_index": 0,
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
"commitment_proof": {
"proof": {
"asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0,
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
},
"taproot_asset_proof": {
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"version": 0
}
},
"tapscript_sibling": ""
},
"tapscript_proof": null
},
"meta_reveal": null,
"additional_inputs": null,
"challenge_witness": null
},
"expected": "0024ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a300000001015000004020ccef4f36280b35bc2969e9c795c93142224c26f9d26580534cd10210b0144a6fd0163b3653e30b279b135fbbeafe21c798724e5cee66ea5a52cb73df63f6d41aa974f064ffff7f200200000002fd018c0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000032201ed4a29f727bd9c9d3c9f190c57dfbe91ef0f6c8f04d63582187c9685eff9daac0004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd01f406fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd02bc06ad01ab0065ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a3000000012fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef301420140731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a8714271507285276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a62700000000000004b008020000092102e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e08020000092102dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16059f0004000000010121024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b70274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06f802c7000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d029c007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b1230303020101079f000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d0274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b04000001bc",
"comment": "valid regtest proof file index 2"
}
],
"error_test_cases": null
}

484
bip-tap-psbt.mediawiki Normal file
View file

@ -0,0 +1,484 @@
<pre>
BIP: ???
Layer: Applications
Title: Taproot Assets PSBT
Author: Oliver Gugger <gugger@gmail.com>
Olaoluwa Osuntokun <laolu32@gmail.com>
Comments-Summary: No comments yet.
Comments-URI: https://git
Status: Draft
Type: Standards Track
Created: 2023-02-24
License: BSD-2-Clause
</pre>
==Abstract==
This document describes the custom fields used in the
[[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki|Partially
Signed Bitcoin Transaction (PSBT, BIP-0174)]] format for Taproot Asset state
transition transactions.
==Copyright==
This document is licensed under the 2-clause BSD license.
==Design==
A Taproot Asset state transition transaction is also referred to as a "virtual
transaction" or asset transfer transaction. The word "virtual" is used to
distinguish between these asset transfers that only happen in the off-chain,
asset overlay context as opposed to "anchor" transactions, which are BTC level
on-chain transaction that commit many asset level transfers to the Bitcoin
chain.
A virtual transaction has many similarities to its Bitcoin wire transaction
counterpart in that it spends one or more asset inputs (asset UTXOs or asset
"coins") and creates one or more new asset outputs.
The main difference to a Bitcoin transaction is that a virtual asset transaction
does not place the witness that satisfies each input's previous output script in
the input itself but instead uses the <code>prev_asset_witnesses</code> field of
the dedicated output that houses the split root asset.
This allows a many-in-many-out virtual transaction to be compressed into a
1-in-1-out transaction (as described in
[[./bip-tap-vm.mediawiki|bip-tap-vm]]) for validation in the Taproot Asset
Virtual Machine.
To assemble the full witness stack that satisfies each input's previous output
script the transaction might need to be signed by multiple parties and/or
devices. This requires the virtual transaction to be passed around among
multiple participants, each adding their part (e.g. signatures) to it. Given the
similarities of virtual transactions to existing Bitcoin transactions, the PSBT
format was chosen as the exchange format for virtual asset state transfers as
well, with a set of new PSBT <code><keytype></code>s as defined in this
document.
==Specification==
A virtual transaction can only contain inputs and outputs of assets that are
fungible among each other. Assets are considered fungible if they either have
the same genesis ID (were minted in the same tranche) or reference the same
<code>group_key</code> (were minted in different tranches).
Within a virtual transaction multiple inputs (asset coins) that have the '''same
genesis ID''' can be merged and split the same way Bitcoin inputs can be merged
and split again. Fungible assets with '''different genesis IDs''' (but same
<code>group_key</code>) can be used together in the same virtual transaction in
order to satisfy a payment request, but merging two fungible assets (with
distinct asset IDs) into the _same_ asset UTXO is disallowed. See the
[[./bip-tap-vm.mediawiki|bip-tap-vm]] for more details.
The construction of the virtual transaction outputs must follow different rules
depending on whether the output is received in an interactive or non-interactive
way by the recipient:
<ul>
<li>
''Interactive:'' The recipient will see the full virtual transaction (e.g. as
a PSBT), including the fully signed new asset leaf. They have all the required
information to be able to fully construct the BTC level anchor output Taproot
key (including the complete asset witness and potentially multiple asset leaves
being committed to in a single BTC level anchor output) to observe the inbound
transfer on chain. Therefore in a scenario where a leaf is sent completely (full
value send), a "split tombstone" (see below) is not required.
</li>
<li>
''Non-interactive'': The recipient has created a Taproot Asset address and is
only watching that Taproot output key on chain. Assets must be committed to the
tree as a split asset, with the split commitment pruned before serializing, to
make the resulting Taproot Asset tree completely predictable for the receiver.
The split commitment and root asset proof will be delivered in the proof file.
A full value send must also be created as a split with the sender creating a
zero value "split tombstone" output with the NUMS point as the script key (see
below).
</li>
</ul>
TODO(guggero): Describe how fungible assets are handled in a non-interactive way
once that is defined.
When splitting an asset UTXO a split commitment is created (as described in
[[./bip-tap-vm.mediawiki|bip-tap-vm]]). The split root is placed in
one of the outputs (often being the change output going back to the sender of
the asset) and marked with the `IsSplitRoot` flag.
If the remaining change of a split is 0, the <code>script_key</code> of the
split root asset output should be the well-known NUMS point (using the string
"taproot-assets" and the traditional "hash and increment" approach to generating
the point) to prove the output cannot be spent further.
This so-called "split tombstone" is required for non-interactive sends (send to
Taproot Asset address) of the full value of a coin.
These zero-value tombstone outputs can be pruned in an interactive scenario in
which the recipient is a ware of the full root asset leaf (including the
TX witness) and can construct the commitment tree root correctly.
==Custom PSBT fields for Taproot Asset virtual transactions==
[[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki|BIP-0174]]
defines roughly 6 global, 24 input and 7 output <code>keytype</code>s. This
leaves enough room for new BIPs to specify additional types without a big risk
of collision. The proprietary type <code>0xFX</code> does not apply to this case
as that is meant for application/vendor specific data, not fields declared in
a BIP.
To further reduce the risk of colliding with key types of other (in-flight) BIPs
we start at the (arbitrarily chosen) value <code>0x70</code> for each section
of new key types.
===Global types===
{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Virtual Transaction Marker
| <tt>PSBT_GLOBAL_TAP_IS_VIRTUAL_TX = 0x70</tt>
| None
| No key data
| <tt><byte 0x01></tt>
| The static marker of <code>0x01</code> to identify this transaction as a
Taproot Asset virtual transaction.
|-
| Taproot Asset Chain HRP
| <tt>PSBT_GLOBAL_TAP_CHAIN_HRP = 0x71</tt>
| None
| No key data
| <tt><string HRP></tt>
| The Human Readable Prefix of the Taproot Asset chain identifier as specified
in [[./bip-tap-addr.mediawiki|bip-tap-addr]].
|-
| Taproot Asset PSBT Version
| <tt>PSBT_GLOBAL_TAP_PSBT_VERSION = 0x72</tt>
| None
| No key data
| <tt><byte version></tt>
| The version of the Taproot Asset PSBT format. Currently <code>0x00</code> is
the only known and supported version.
|}
===Input types===
{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Previous Asset Leaf
| <tt>PSBT_IN_TAP_PREV_ID = 0x70</tt>
| None
| No key data
| <tt><tlv_blob prev_asset_id></tt>
| The previous asset leaf (identified by
<code>prev_outpoint || asset_id || asset_script_hash</code>) in TLV format as
defined in [[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|-
| Anchor Output Value
| <tt>PSBT_IN_TAP_ANCHOR_VALUE = 0x71</tt>
| None
| No key data
| <tt><64-bit big endian int value></tt>
| The value in satoshis of the BTC level anchor output that committed to the
asset input being spent.
|-
| Anchor Output <code>pkScript</code>
| <tt>PSBT_IN_TAP_ANCHOR_PK_SCRIPT = 0x72</tt>
| None
| No key data
| <tt><bytes pkScript></tt>
| The <code>pkScript</code> of the BTC level anchor output that committed to the
asset input being spent.
|-
| Anchor Output Sighash Type
| <tt>PSBT_IN_TAP_ANCHOR_SIGHASH_TYPE = 0x73</tt>
| None
| No key data
| <tt><64-bit big endian int sighash type></tt>
| The 64-bit big endian unsigned integer specifying the sighash type to be used
for the BTC level anchor output that committed to the asset input being spent.
|-
| Anchor Output Taproot Internal Key
| <tt>PSBT_IN_TAP_ANCHOR_TAP_INTERNAL_KEY = 0x74</tt>
| None
| No key data
| <tt><32-byte xonlypubkey></tt>
| The X-only pubkey used as the internal key of the BTC level anchor output that
committed to the asset input being spent.
|-
| Anchor Output Taproot Merkle Root
| <tt>PSBT_IN_TAP_ANCHOR_TAP_MERKLE_ROOT = 0x75</tt>
| None
| No key data
| <tt><32-byte hash></tt>
| The 32 byte Merkle root hash of the BTC level anchor output that committed to
the asset input being spent.
|-
| Anchor Output BIP-0032 Derivation Path
| <tt>PSBT_IN_TAP_ANCHOR_BIP32_DERIVATION = 0x76</tt>
| <tt><bytes pubkey></tt>
| The public key
| <tt><4 byte fingerprint> <32-bit little endian uint path element>*</tt>
| The master key fingerprint as defined by BIP-0032 concatenated with the
derivation path of the public key that was used for the BTC level anchor output
that committed to the asset input being spent. The derivation path is
represented as 32 bit unsigned integer indexes concatenated with each other.
Public keys are those that will be needed to sign this input.
|-
| Anchor Output Taproot Key BIP 32 Derivation Path
| <tt>PSBT_IN_TAP_ANCHOR_TAP_BIP32_DERIVATION = 0x77</tt>
| <tt><32 byte xonlypubkey></tt>
| A 32 byte X-only public key involved in this input. It may be the output key,
the internal key, or a key present in a leaf script.
| <tt><compact size uint number of hashes> <32 byte leaf hash>*
<4 byte fingerprint> <32-bit little endian uint path element>*</tt>
| A compact size unsigned integer representing the number of leaf hashes,
followed by a list of leaf hashes, followed by the 4 byte master key fingerprint
concatenated with the derivation path of the public key. The derivation path is
represented as 32-bit little endian unsigned integer indexes concatenated with
each other. Public keys are those needed to spend this output. The leaf hashes
are of the leaves which involve this public key. The internal key does not have
leaf hashes, so can be indicated with a <tt>hashes len</tt> of 0. Finalizers
should remove this field after <tt>PSBT_IN_FINAL_SCRIPTWITNESS</tt> is
constructed.
|-
| Anchor Output Tapscript Sibling
| <tt>PSBT_IN_TAP_ANCHOR_TAPSCRIPT_SIBLING = 0x78</tt>
| None
| No key data
| <tt><byte sibling_type><compact size num_bytes><bytes tapscript sibling preimage></tt>
| The preimage of the tapscript sibling that is on the same level as the Taproot
Asset commitment that was committed to in the anchor. If this is not present,
then the Taproot Asset commitment is the only script leaf in the tree.
|-
| Taproot Asset Asset
| <tt>PSBT_IN_TAP_ASSET = 0x79</tt>
| None
| No key data
| <tt><tlv_blob asset></tt>
| The full input asset leaf that is being spent, in TLV format as defined in
[[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|-
| Taproot Asset Proof
| <tt>PSBT_IN_TAP_ASSET_PROOF = 0x7a</tt>
| None
| No key data
| <tt><tlv_blob proof></tt>
| The last proof of the input asset being spent, in TLV format as defined in
[[./bip-tap-proof-file.mediawiki#file-serialization|
bip-tap-proof-file File Serialization]].
|}
===Output types===
{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Type
| <tt>PSBT_OUT_TAP_TYPE = 0x70</tt>
| None
| No key data
| <tt><byte output_type></tt>
| A <code>uint8</code> value indicating the type of the virtual output. Valid
values are: 0x00 (<tt>Simple</tt>), 0x01 (<tt>SplitRoot</tt>),
0x02 (<tt>PassiveAssetsOnly</tt>), 0x03 (<tt>PassiveSplitRoot</tt>), see
description below.
|-
| Is Interactive
| <tt>PSBT_OUT_TAP_IS_INTERACTIVE = 0x71</tt>
| None
| No key data
| <tt><byte 0x00/0x01></tt>
| A boolean value indicating whether the recipient of the output is aware of the
full asset leaf they are receiving (=interactive) or not (=non-interactive). In
the non-interactive case, the recipient will expect this output to be a split
output.
|-
| Anchor Output Index
| <tt>PSBT_OUT_TAP_ANCHOR_OUTPUT_INDEX = 0x72</tt>
| None
| No key data
| <tt><64-bit big endian int value></tt>
| The Bitcoin level anchor transaction output index this asset output is going
to be committed to.
|-
| Anchor Output Taproot Internal Key
| <tt>PSBT_OUT_TAP_ANCHOR_TAP_INTERNAL_KEY = 0x73</tt>
| None
| No key data
| <tt><32-byte xonlypubkey></tt>
| The X-only pubkey used as the internal key of the BTC level anchor output that
will be committing to the asset output.
|-
| Anchor Output BIP-0032 Derivation Path
| <tt>PSBT_OUT_TAP_ANCHOR_BIP32_DERIVATION = 0x74</tt>
| <tt><bytes pubkey></tt>
| The public key
| <tt><4 byte fingerprint> <32-bit little endian uint path element>*</tt>
| The master key fingerprint as defined by BIP-0032 concatenated with the
derivation path of the public key that will be used for the BTC level anchor
output that is committing to the asset output. The derivation path is
represented as 32 bit unsigned integer indexes concatenated with each other.
Public keys are those that will be needed to sign this input.
|-
| Anchor Output Taproot Key BIP-0032 Derivation Path
| <tt>PSBT_OUT_TAP_ANCHOR_TAP_BIP32_DERIVATION = 0x75</tt>
| <tt><32 byte xonlypubkey></tt>
| A 32 byte X-only public key involved in this input. It may be the output key,
the internal key, or a key present in a leaf script.
| <tt><compact size uint number of hashes> <32 byte leaf hash>*
<4 byte fingerprint> <32-bit little endian uint path element>*</tt>
| A compact size unsigned integer representing the number of leaf hashes,
followed by a list of leaf hashes, followed by the 4 byte master key fingerprint
concatenated with the derivation path of the public key. The derivation path is
represented as 32-bit little endian unsigned integer indexes concatenated with
each other. Public keys are those needed to spend this output. The leaf hashes
are of the leaves which involve this public key. The internal key does not have
leaf hashes, so can be indicated with a <tt>hashes len</tt> of 0. Finalizers
should remove this field after <tt>PSBT_IN_FINAL_SCRIPTWITNESS</tt> is
constructed.
|-
| Taproot Asset
| <tt>PSBT_OUT_TAP_ASSET = 0x76</tt>
| None
| No key data
| <tt><tlv_blob asset></tt>
| The full output asset leaf being created, in TLV format as defined in
[[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|-
| Taproot Asset Split Asset
| <tt>PSBT_OUT_TAP_SPLIT_ASSET = 0x77</tt>
| None
| No key data
| <tt><tlv_blob split_asset></tt>
| In case the asset serialized in the <tt>PSBT_OUT_TAP_ASSET</tt> is a split
root (<tt>PSBT_OUT_TAP_IS_SPLIT_ROOT=0x01</tt>), this field houses the created
split asset at the root locator that contains the split commitment witness. This
is used for validation only and isn't committed to in any tree. If present the
split asset is encoded in TLV format as defined in
[[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|-
| Anchor Output Tapscript Sibling
| <tt>PSBT_OUT_TAP_ANCHOR_TAPSCRIPT_SIBLING = 0x78</tt>
| None
| No key data
| <tt><byte sibling_type><compact size num_bytes><bytes tapscript sibling preimage></tt>
| The preimage of the tapscript sibling that is on the same level as the Taproot
Asset commitment that was committed to in the anchor. If this is not present,
then the Taproot Asset commitment is the only script leaf in the tree.
|}
===Values for <tt>PSBT_OUT_TAP_TYPE</tt>===
The <tt>PSBT_OUT_TAP_TYPE</tt> field describes the type of virtual output. This
type has an influence on how an asset needs to be signed or whether there is an
asset at all in an output.
The following values are defined:
<ul>
<li><b>Simple</b> (<tt>0x00</tt>) is a plain full-value or split output that is
not a split root and does not carry passive assets. In case of a split, the
asset of this output has a split commitment.
</li>
<li><b>SplitRoot</b> (<tt>0x01</tt>) is a split root output that carries the
change from a split or a tombstone from a non-interactive full value send
output. In either case, the asset of this output has a tx witness.
</li>
<li><b>PassiveAssetsOnly</b> (<tt>0x02</tt>) indicates that this output only
carries passive assets and therefore the asset in this output is nil. The
passive assets themselves are signed in their own virtual transactions and
are not present in this packet.
</li>
<li><b>PassiveSplitRoot</b> (<tt>0x03</tt>) is a split root output that carries
the change from a split or a tombstone from a non-interactive full value send
output, as well as passive assets.
</li>
</ul>
==Committing Taproot Asset virtual transactions into a BTC level anchor transaction==
The above section defined new fields for representing a virtual asset
transaction. This section explains how one or multiple virtual asset
transactions can be mapped to and be committed to in a single Bitcoin level
on-chain "anchor" transaction.
The following steps should be taken for committing one or more Taproot Asset
virtual transactions onto a single BTC anchor transaction:
# Sign the virtual transaction as described in [[./bip-tap.mediawiki|bip-tap]].
# Validate that each input in each virtual transaction has the necessary anchor information set (<code>PSBT_IN_TAP_ANCHOR_*</code>).
# Validate that each output in each virtual transaction has the necessary anchor information set (<code>PSBT_OUT_TAP_ANCHOR_*</code>).
# Validate that each virtual input's anchor information referencing the same previous outpoint (<code>PSBT_IN_TAP_PREV_ID.prev_outpoint</code>) is the same as all fields should refer to the same on-chain unspent output.
# Validate that each virtual output's anchor information referencing the same anchor output index (<code>PSBT_OUT_TAP_ANCHOR_OUTPUT_INDEX</code>) is the same as all fields should refer to the same on-chain output being created.
# For each input, add the last transition proof of the input asset to the BTC anchor PSBT input (field <code>PSBT_IN_TAP_PROOF</code>).
# For each unique anchor output index, create an output on the BTC anchor transaction:
## Merge all assets into a single Taproot Asset tree.
## If a Tapscript sibling is present for the BTC anchor output, verify it is not a Taproot Asset commitment.
## Calculate the merkle root hash from the merged Taproot Asset tree and the optional Tapscript sibling.
## Calculate the Taproot output key from the internal key and the merkle root hash, update the <code>pkScript</code> of the BTC anchor output.
# Create a single transition proof for each of the virtual transaction outputs and add them to the BTC anchor output, keyed by each asset's <code>script_key</code> (field <code>PSBT_OUT_TAP_PROOF</code>).
Once the BTC level anchor transaction has the extra information attached, it can
then be passed to all signers to produce the necessary signatures for getting it
finalized.
==Custom PSBT fields for BTC level anchor transactions==
===Input types===
{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Taproot Asset Proof
| <tt>PSBT_IN_TAP_PROOF = 0x70</tt>
| <tt><32 byte xonlyscriptkey></tt>
| The 32 byte X-only script key of the input asset being spent.
| <tt><tlv_blob proof></tt>
| The last proof of the input asset being spent, in TLV format as defined in
[[./bip-tap-proof-file.mediawiki#file-serialization|bip-tap-proof-file File Serialization]].
|}
===Output types===
{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Taproot Asset Proof
| <tt>PSBT_OUT_TAP_PROOF = 0x70</tt>
| <tt><32 byte xonlyscriptkey></tt>
| The 32 byte X-only script key of the input asset being spent.
| <tt><tlv_blob proof></tt>
| The new transition proof(s) for the new asset(s) created in this output.
|}
==Test Vectors==
Test vectors for [[Custom PSBT fields for Taproot Asset virtual transactions]]
can be found here:
* [[bip-tap-psbt/psbt_encoding_generated.json|PSBT encoding test vectors]]
* [[bip-tap-psbt/psbt_encoding_error_cases.json|PSBT encoding error test vectors]]
The test vectors are automatically generated by
[https://github.com/lightninglabs/taproot-assets/tree/main/tappsbt unit tests in
the Taproot Assets GitHub repository].
==Reference Implementation==
github.com/lightninglabs/taproot-assets/tree/main/tappsbt

View file

@ -0,0 +1,8 @@
{
"error_test_cases": [
{
"packet": {},
"error": "missing chain params HRP"
}
]
}

View file

@ -0,0 +1,395 @@
{
"valid_test_cases": [
{
"packet": {
"inputs": [
{
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": "",
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "6abedfb7cc21821085134aec85f1ec2335aae36608efb88578042e2d29a137f2",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"anchor": {
"value": 0,
"pk_script": "",
"sig_hash_type": 0,
"internal_key": "",
"merkle_root": "",
"tapscript_sibling": "",
"bip32_derivation": null,
"tr_bip32_derivation": null
},
"asset": null,
"proof": ""
}
],
"outputs": [
{
"amount": 0,
"type": 1,
"interactive": false,
"anchor_output_index": 0,
"anchor_output_internal_key": "",
"anchor_output_bip32_derivation": null,
"anchor_output_tr_bip32_derivation": null,
"anchor_output_tapscript_sibling": "",
"asset": null,
"split_asset": null,
"pk_script": "51207c79b9b26e463895eef5679d8558942c86c4ad2233adef01bc3e6d540b3653fe",
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": ""
},
{
"amount": 5263531936693774911,
"type": 0,
"interactive": false,
"anchor_output_index": 1,
"anchor_output_internal_key": "034a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3",
"anchor_output_bip32_derivation": null,
"anchor_output_tr_bip32_derivation": null,
"anchor_output_tapscript_sibling": "",
"asset": null,
"split_asset": null,
"pk_script": "5120458a92cc12d01b8e8892da58ed511d398f2ce42b4d6295cf0c66346249f4d306",
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": ""
},
{
"amount": 0,
"type": 0,
"interactive": false,
"anchor_output_index": 0,
"anchor_output_internal_key": "",
"anchor_output_bip32_derivation": null,
"anchor_output_tr_bip32_derivation": null,
"anchor_output_tapscript_sibling": "",
"asset": null,
"split_asset": null,
"pk_script": "51209bfdf06c3322b3f3fde43d9c13db6b5c5882f69fbba6a958c1312f48e1c71b11",
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": ""
}
],
"version": 0,
"chain_params_hrp": "tapbc"
},
"expected": "cHNidP8BALQCAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAIlEgfHm5sm5GOJXu9WedhViULIbErSIzre8BvD5tVAs2U/4/ao62aNILSSJRIEWKkswS0BuOiJLaWO1RHTmPLOQrTWKVzwxmNGJJ9NMGAAAAAAAAAAAiUSCb/fBsMyKz8/3kPZwT22tcWIL2n7umqVjBMS9I4ccbEQAAAAABcAEBAXEFdGFwYmMBcgEAAAFwZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGq+37fMIYIQhRNK7IXx7CM1quNmCO+4hXgELi0poTfyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXEIAAAAAAAAAAABcgABcwgAAAAAAAAAAAF1AAF4AAF6AAABcAEBAXEBAAFyCAAAAAAAAAAAAAFwAQABcQEAAXIIAAAAAAAAAAEBcyEDSoIdXsAIcSmDkp3kSLivtsJOWhuXNnuaZbYiDX8IP+MAAXABAAFxAQABcggAAAAAAAAAAAA=",
"comment": "minimal packet"
},
{
"packet": {
"inputs": [
{
"bip32_derivation": [
{
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"tr_bip32_derivation": [
{
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"leaf_hashes": [],
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"tr_internal_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"tr_merkle_root": "6d65726b6c6520726f6f74",
"prev_id": {
"out_point": "42c29291018d7c2d968d3f71f8cb984b92f67403049442fd5ad145f422b02936:4104515131",
"asset_id": "9d17346865fcf92b0c3a17c9028be9914eb7649c6c9347800979d1830356f2a5",
"script_key": "035f01644ac40614b96363ba9baf1a7381a7bac742d267909edac6eebfc3eba5e7"
},
"anchor": {
"value": 777,
"pk_script": "616e63686f7220706b736372697074",
"sig_hash_type": 3,
"internal_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"merkle_root": "6d65726b6c6520726f6f74",
"tapscript_sibling": "7369626c696e67",
"bip32_derivation": [
{
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"tr_bip32_derivation": [
{
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"leaf_hashes": [],
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
]
},
"asset": {
"version": 0,
"genesis_first_prev_out": "7d07c649581eeb39b5a315724c7af14fa459169873f5f1017fbc897d067403de:424111158",
"genesis_tag": "24e2cafccae3a61fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6",
"genesis_meta_hash": "24e2cafccae3a61fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6",
"genesis_output_index": 1864800808,
"genesis_type": 0,
"amount": 6735196588112087611,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "022b6089025115cd1c390a01476da56cc20d9dbf4f571bc883623fb027aa2c7a98",
"group_key": {
"group_key": "0275c517d5ed149ebee5735da50d8cc59ac6378436e000138561abd6c437d02d13",
"group_key_sig": "a2fbac47445855f2fdabf95ef55fd268819eed6de205e2397275ac08010d1724e1edb93f6d656719896df16c350f5004b8ad5913f043b5648b3b70bf98b01a0e"
}
},
"proof": "7468697320697320612070726f6f66"
},
{
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": "",
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"anchor": {
"value": 0,
"pk_script": "",
"sig_hash_type": 0,
"internal_key": "",
"merkle_root": "",
"tapscript_sibling": "",
"bip32_derivation": null,
"tr_bip32_derivation": null
},
"asset": null,
"proof": ""
}
],
"outputs": [
{
"amount": 123,
"type": 1,
"interactive": true,
"anchor_output_index": 0,
"anchor_output_internal_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"anchor_output_bip32_derivation": [
{
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"anchor_output_tr_bip32_derivation": [
{
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"leaf_hashes": [],
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"anchor_output_tapscript_sibling": "00c0126e6f7420612076616c696420736372697074",
"asset": {
"version": 0,
"genesis_first_prev_out": "f665a6a780ea967cd7101f46e83699caf3a08e4b738b68290b0d22050143a661:2783629501",
"genesis_tag": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
"genesis_meta_hash": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
"genesis_output_index": 637353343,
"genesis_type": 0,
"amount": 8267293389953062912,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
"group_key": {
"group_key": "023a8b6353a798347b45a15b2c2348799aaa3a3290f1bd91896b310b01acf3b572",
"group_key_sig": "de8faf83e95caae8472ca4b268ebaa6940c5166616999c71344c1b9fda5af81a515e31f183b1a4e7957beb4241f0e264c1b52935524710fa6f7a39787417bba5"
}
},
"split_asset": {
"version": 0,
"genesis_first_prev_out": "f665a6a780ea967cd7101f46e83699caf3a08e4b738b68290b0d22050143a661:2783629501",
"genesis_tag": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
"genesis_meta_hash": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
"genesis_output_index": 637353343,
"genesis_type": 0,
"amount": 8267293389953062912,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
"group_key": {
"group_key": "023a8b6353a798347b45a15b2c2348799aaa3a3290f1bd91896b310b01acf3b572",
"group_key_sig": "de8faf83e95caae8472ca4b268ebaa6940c5166616999c71344c1b9fda5af81a515e31f183b1a4e7957beb4241f0e264c1b52935524710fa6f7a39787417bba5"
}
},
"pk_script": "5120b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": ""
},
{
"amount": 345,
"type": 1,
"interactive": false,
"anchor_output_index": 1,
"anchor_output_internal_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"anchor_output_bip32_derivation": [
{
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"anchor_output_tr_bip32_derivation": [
{
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
"leaf_hashes": [],
"fingerprint": 0,
"bip32_path": [
2147484665,
2147483648,
2147483771,
0,
456
]
}
],
"anchor_output_tapscript_sibling": "01197ce22d12bc5a99587533af41169fa1dc9ff866c0d4d3021158d62933672d11197ce22d12bc5a99587533af41169fa1dc9ff866c0d4d3021158d62933672d11",
"asset": {
"version": 0,
"genesis_first_prev_out": "f665a6a780ea967cd7101f46e83699caf3a08e4b738b68290b0d22050143a661:2783629501",
"genesis_tag": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
"genesis_meta_hash": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
"genesis_output_index": 637353343,
"genesis_type": 0,
"amount": 8267293389953062912,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 0,
"script_key": "02b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
"group_key": {
"group_key": "023a8b6353a798347b45a15b2c2348799aaa3a3290f1bd91896b310b01acf3b572",
"group_key_sig": "de8faf83e95caae8472ca4b268ebaa6940c5166616999c71344c1b9fda5af81a515e31f183b1a4e7957beb4241f0e264c1b52935524710fa6f7a39787417bba5"
}
},
"split_asset": null,
"pk_script": "5120b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
"bip32_derivation": null,
"tr_bip32_derivation": null,
"tr_internal_key": "",
"tr_merkle_root": ""
}
],
"version": 0,
"chain_params_hrp": "tapbc"
},
"expected": "cHNidP8BALICAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACewAAAAAAAAAiUSCy0NlDWyqX4J2nNmUEi/rc6/vhe2+lctlVvBHl1mX2iVkBAAAAAAAAIlEgstDZQ1sql+CdpzZlBIv63Ov74XtvpXLZVbwR5dZl9okAAAAAAXABAQFxBXRhcGJjAXIBAAAiBgK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhFr+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABFyC/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDAEYC21lcmtsZSByb290AXBlNimwIvRF0Vr9QpQEA3T2kkuYy/hxP42WLXyNAZGSwkL0pe47nRc0aGX8+SsMOhfJAovpkU63ZJxsk0eACXnRgwNW8qUDXwFkSsQGFLljY7qbrxpzgae6x0LSZ5Ce2sbuv8PrpecBcQgAAAAAAAADCQFyD2FuY2hvciBwa3NjcmlwdAFzCAAAAAAAAAADAXQhAr+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMAXULbWVya2xlIHJvb3QidgK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhd7+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABeAdzaWJsaW5nAXn9kgEAAQABit4DdAZ9ibx/AfH1c5gWWaRP8XpMchWjtTnrHlhJxgd9GUdsNkAyNGUyY2FmY2NhZTNhNjFmYjU4NmIxNDMyM2E2YmM4ZjllN2RmMWQ5MjkzMzNmZjk5MzkzM2JlYTZmNWIzYWY2JOLK/Mrjph+1hrFDI6a8j5598dkpMz/5k5M76m9bOvZvJpooAAIBAAMJ/114OZy+2Ao7BmkBZwBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAgAACSECK2CJAlEVzRw5CgFHbaVswg2dv09XG8iDYj+wJ6osepgKYQJ1xRfV7RSevuVzXaUNjMWaxjeENuAAE4Vhq9bEN9AtE6L7rEdEWFXy/av5XvVf0miBnu1t4gXiOXJ1rAgBDRck4e25P21lZxmJbfFsNQ9QBLitWRPwQ7Vkiztwv5iwGg4Beg90aGlzIGlzIGEgcHJvb2YAAXBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcQgAAAAAAAAAAAFyAAFzCAAAAAAAAAAAAXUAAXgAAXoAAAFwAQEBcQEBAXIIAAAAAAAAAAABcyECv4/i9yXzNXO3fmnoPDbw1203XNvB41CFUMxZxbYnyQwidAK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhdb+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABdv2SAQABAAGKYaZDAQUiDQspaItzS46g88qZNuhGHxDXfJbqgKemZfal6tC9QDk5M2ViZGY4ODhiMDQ4ODNlNTZhMTU2YThkZTU2M2FmYTQ2N2Q0OWRlYzZhNDBlOWExZDAwN2YwMzNjMjgyMzCZPr34iLBIg+VqFWqN5WOvpGfUnexqQOmh0AfwM8KCMCX9PX8AAgEAAwn/crtTiUIWWAAGaQFnAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCAAAJIQKy0NlDWyqX4J2nNmUEi/rc6/vhe2+lctlVvBHl1mX2iQphAjqLY1OnmDR7RaFbLCNIeZqqOjKQ8b2RiWsxCwGs87Vy3o+vg+lcquhHLKSyaOuqaUDFFmYWmZxxNEwbn9pa+BpRXjHxg7Gk55V760JB8OJkwbUpNVJHEPpvejl4dBe7pQF3/ZIBAAEAAYphpkMBBSINCyloi3NLjqDzypk26EYfENd8luqAp6Zl9qXq0L1AOTkzZWJkZjg4OGIwNDg4M2U1NmExNTZhOGRlNTYzYWZhNDY3ZDQ5ZGVjNmE0MGU5YTFkMDA3ZjAzM2MyODIzMJk+vfiIsEiD5WoVao3lY6+kZ9Sd7GpA6aHQB/AzwoIwJf09fwACAQADCf9yu1OJQhZYAAZpAWcAZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAIAAAkhArLQ2UNbKpfgnac2ZQSL+tzr++F7b6Vy2VW8EeXWZfaJCmECOotjU6eYNHtFoVssI0h5mqo6MpDxvZGJazELAazztXLej6+D6Vyq6EcspLJo66ppQMUWZhaZnHE0TBuf2lr4GlFeMfGDsaTnlXvrQkHw4mTBtSk1UkcQ+m96OXh0F7ulAXgVAMASbm90IGEgdmFsaWQgc2NyaXB0AAFwAQEBcQEAAXIIAAAAAAAAAAEBcyECv4/i9yXzNXO3fmnoPDbw1203XNvB41CFUMxZxbYnyQwidAK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhdb+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABdv2SAQABAAGKYaZDAQUiDQspaItzS46g88qZNuhGHxDXfJbqgKemZfal6tC9QDk5M2ViZGY4ODhiMDQ4ODNlNTZhMTU2YThkZTU2M2FmYTQ2N2Q0OWRlYzZhNDBlOWExZDAwN2YwMzNjMjgyMzCZPr34iLBIg+VqFWqN5WOvpGfUnexqQOmh0AfwM8KCMCX9PX8AAgEAAwn/crtTiUIWWAAGaQFnAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCAAAJIQKy0NlDWyqX4J2nNmUEi/rc6/vhe2+lctlVvBHl1mX2iQphAjqLY1OnmDR7RaFbLCNIeZqqOjKQ8b2RiWsxCwGs87Vy3o+vg+lcquhHLKSyaOuqaUDFFmYWmZxxNEwbn9pa+BpRXjHxg7Gk55V760JB8OJkwbUpNVJHEPpvejl4dBe7pQF4QQEZfOItErxamVh1M69BFp+h3J/4ZsDU0wIRWNYpM2ctERl84i0SvFqZWHUzr0EWn6Hcn/hmwNTTAhFY1ikzZy0RAA==",
"comment": "random packet"
}
],
"error_test_cases": null
}

718
bip-tap-universe.mediawiki Normal file
View file

@ -0,0 +1,718 @@
<pre>
BIP: ???
Layer: Applications
Title: Taproot Asset Universes
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
</pre>
==Abstract==
Taproot Asset provenance is defined by the lineage of an asset all the way back
to the genesis point, which is the outpoint that the unique asset identifier is
derived from. A Taproot Asset Universe is proposed as a way for users/holders
of an asset to easily bootstrap their recognition of a given genesis point as
the root of an asset. A Universe is an MS-SMT that indexes into the set of
spent outpoints that track asset movement/transfer. A Universe can contain the
set of genesis outpoints for an asset, several assets, track individual
transactions, and also be used as an aggregation layer.
==Copyright==
This document is licensed under the 2-clause BSD license.
==Motivation==
In order to give users/holders of an asset an easy way to bootstrap provenance,
as well as track the total amount of units issued for a given asset, an
on-chain merkleized indexing structure is necessary. Further, if we define
constraints w.r.t how a "canonical" Universe can be updated, then users are
able to watch a set of on-chain outputs to be notified of further chain
issuance. Continuing to build off this structure, if users are able to maintain
a trust relationship with the issuer of an asset (say the asset belongs to a
closed source game), then they can delegate update rights to a single or
federated set of parties, allowing them to bundle several asset updates in a
single transaction, thereby scaling on-chain transfers.
==Design==
A Taproot Asset Universe MS-SMT differs from the normal MS-SMT in that the key
index of the lowest tree is derived from an ''outpoint'' and `script key``
rather than an asset script key as given an outpoint where an asset ''was''
present, the asset Universe maps to the Taproot Asset transaction+spending meta
data. Given this outpoint indexing structure, if we create a new "re genesis"
(to create a virtual tx graph) outpoint, then we can construct a new virtual
Taproot Asset transaction graph which provably tracks the movement of assets in
an off-chain manner, relying on a single or federated party to handle updates.
===Specification===
====Asset Universes====
An Asset Universe is a publicly audit able merkle-sum sparse merkle tree
(MS-SMT) over one or several assets. Unlike the normal Taproot Asset tree, a
Universe isn't used to custody Taproot Assets. Instead, a Universe commits to a
subset of the history of one, or many assets. A close analogue to a public
Universe is a block explorer. A Universe can be used to:
* Bootstrap proof verification by committing to the set of genesis outputs.
* Generate more compact proofs w/ an additional trust assumption.
* Audit to the total amount of units in existence for a given asset.
* Track new asset issuance for a given asset ID.
Universes can also be used to essentially compress the history of a series of
transfers into a single on-chain transaction. This variant is called a Pocket
Universe. From this PoV, a Pocket Universe can be seen as a sort of Taproot
Asset channel wherein one party (or a consortium/threshold of them) can batch
update a tree to clear countless transfers in a single on-chain transaction.
Such a Universe can also be created over multiple assets, effectively becoming
a Universe of Universes, or a ''Multiverse''.
During asset creation, the party creating the asset (identified by it's all
zero <code>prev_asset_id</code> value) MAY also specify a
<code>canonical_universe</code> field which specifies additional constraints
on the set of outputs produced. Namely, if this field is specified during asset
creation, then the ''first'' output of the next spend after the genesis
outpoint MUST commit to an updated base Universe that indexes into the prior
genesis outpoint spend (asset creation). In addition, the internal key used for
the output MUST be the <code>asset_group_key</code> field specified during
asset creation. After each subsequent asset issuance event, this output SHOULD
be updated to commit to the new updated base Universe that indexes into all
asset issuance transactions on chain.
Specifying a key effectively blesses a public key on-chain, allowing it to be
used to commit to the "canonical" history of an asset. In addition, those
wishing to be "notified" of new asset issuance can watch this output on-chain
to track any modifications.
====Root Universes & Genesis Asset Verification====
Unlike a normal Taproot Asset asset tree, a base Universe for a given asset
only commits to the set of ''genesis outpoints'' for an asset. The value for
each of the leaves contains enough information to fully verify the existence of
the transaction that created the asset. As this type of Universe only commits
to the set of constituent assets present at the Beginning, that all other
transfers depend on, we call this a ''Root'' Universe.
Such a Universe can be used to bootstrap provenance and proof verification, as
assuming a party knows which Universe to query, they're able to verify the
provenance of a purported valid asset. In addition to bootstrapping provenance
verification, as Universe trees are themselves an MS-SMT, they can be used to
audit the total amount of a given asset in existence.
A Root Universe, is an MS-SMT with the following structure:
* The MS-SMT root commits to the sum of the total set of issued assets for a given <code>genesisAssetID</code>
** A <code>genesisAssetID</code> can either be a normal <code>assetID</code> or <code>sha256(asset_group_key)</code>. In the latter case, all values in the tree MUST share the same <code>asset_group_key</code>.
** <code>key</code>: an <code>sha256(outpoint || scriptKey)</code>. Given the asset ID, this uniquely locates a new minting event in the target outpoint.
** <code>value</code>: <code>universe_proof_leaf</code>
** <code>sum_value</code>: the total amount of asset units issued by the proof leaf.
The key of the Root Universe is a serialized Bitcoin outpoint. As a result, the
Universe structure can be used to query for the existence of Taproot Assets
rooted at a given outpoint. For a Root Universe, the only outpoints tracked are
outpoints that ''create'' a Taproot Asset asset.
As the MS-SMT is keyed by the <code>sha256(outpoint || scriptKey)</code>, it
can be used to bootstrap any proof verification of a purported asset, as the
initial linkage is dependent on the provenance of the referenced
<code>genesisOutpoint</code> (verification starts at the Beginning and works
backwards).
A <code>universe_proof_leaf</code>: is the state transition proof from
<code>bip-tap-proof-file.mediawiki</code> format:
* type: 0 (<code>prev_out</code>)
** value:
*** [<code>36*byte</code>:<code>txid || output_index</code>]
* type: 1 (<code>block_header</code>)
** value:
*** [<code>80*byte</code>:<code>bitcoin_header</code>]
* type: 2 (<code>anchor_tx</code>)
** value:
*** [<code>...*byte</code>:<code>serialized_bitcoin_tx</code>]
* type: 3 (<code>anchor_tx_merkle_proof</code>)
** value:
*** [<code>...*byte</code>:<code>merkle_inclusion_proof</code>]
* type: 4 (<code>taproot_asset_leaf</code>)
** value:
*** [<code>tlv_blob</code>:<code>serialized_tlv_leaf</code>]
* type: 5 (<code>taproot_asset_inclusion_proofs</code>)
** value:
*** [<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
**** type: 0 (<code>output_index</code>
***** value: [<code>int32</code>:<code>index</code>]
**** type: 1 (<code>internal_key</code>
***** value: [<code>33*byte</code>:<code>y_parity_byte || schnorr_x_only_key</code>]
**** type: 2 (<code>taproot_asset_proof</code>)
***** value: [<code>...*byte</code>:<code>asset_proof</code>]
****** type: 0 (<code>taproot_asset_proof</code>)
******* value: [<code>...*byte</code>:<code>asset_inclusion_proof</code>]
******* type: 0
******** value: [<code>uint32</code>:<code>proof_version</code>]
******* type: 1
******** value: [<code>32*byte</code>:<code>asset_id</code>]
******* type: 2
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
****** type: 1 (<code>taproot_asset_inclusion_proof</code>)
******* value: [<code>...*byte</code>:<code>taproot_asset_inclusion_proof</code>]
******* type: 0
******** value: [<code>uint32</code>:<code>proof_version</code>]
******* type: 1
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
******* type: 2 (<code>taproot_sibling_preimage</code>)
******** value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
**** type: 3 (<code>taproot_asset_commitment_exclusion_proof</code>
***** value: [<code>...*byte</code>:<code>taproot_exclusion_proof</code>]
****** type: 0 (<code>tap_image_1</code>)
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
****** type: 1 (<code>tap_image_2</code>)
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
* type: 6 (<code>taproot_exclusion_proofs</code>)
** value:
*** [<code>uint16</code>:<code>num_proofs</code>][<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
This is the same state transition proof that would be used to prove asset
creation to a third party. The leaf value of the Root Universe allows
verifiers to fully verify the creation of the asset based on the genesis
outpoint spent.
=====Canonical Root Universe State Transition Rules=====
In order to provide an authoritative source of truth for the supply and
issuance events of a given asset, an asset MAY specify a Canonical Root
Universe at initial minting time. If the <code>canonical_universe</code> TLV is
present in the genesis asset, then the following restrictions MUST be applied
to subsequent transactions that spend the minting output:
* When the minting output is spent, the ''first'' output of the resulting transaction MUST:
** Use the internal key of the revealed <code>asset_group_key</code> as the internal key of the V1 Taproot witness program.
** The tapscript tree of the newly created output MUST contain a new Root Universe commitment that includes the initial minting event.
** We refer to this output as the <code>root_asset_commitment</code>.
*** If multiple assets within a singular <code>asset_group</code> were issued in the prior transaction, then the Root Universe MUST contain all new assets.
* For assets that were issued with an <code>asset_group_key</code>, each time a new asset is issued:
** The latest unspent <code>root_asset_commitment</code> output MUST be spent.
*** This serves to link new issuance events, with the reveal of a new Canonical Root Universe hash.
** The ''first'' output of this spending transaction inherits the requirements above:
*** A new updated Root Universe commitment is included in the <code>root_asset_commitment</code>.
*** This new <code>root_asset_commitment</code> becomes the new updated supply anchor for the asset.
The stated rules above effectively serve as an iterated commit and reveal game.
Each time a new asset is issued (the issuance commitment spent), then the first
output of the resulting transaction MUST commit to the new Root Universe hash.
All other subsequent issuance events MUST then spend that same output, updating
the commitment to the Root Universe hash.
As a result of the above chain commitment structure, all queries against for
the latest Canonical Root Universe of an asset can be authenticated using a
series of merkle proofs:
* A merkle proof anchored in the block header that mined the transaction with the <code>root_asset_commitment</code>.
* A tapscript merkle proof to show the Root Universe hash is included in the tapscript tree.
* A MS-SMT merkle proof to show that the asset being verified is indeed part of the Root Universe commitment chain.
In order to enforce uniqueness of the Root Universe has commitment, we leverage
the same tapscript commitment uniqueness rules in
<code>bip-tap.mediawiki</code>. We use a modified commitment structure of:
* <code>tagged_hash("TapLeaf", leaf_version || universe_marker || universe_version || root_universe_hash)</code>
where:
* <code>universe_marker</code>: is the `sha256` hash of the ascii string "universe".
* <code>universe_version<code>: is the version of the Universe commitment used.
* <code>root_universe_hash<code>: is the root hash of the Root Universe.
As the Root Universe for a given asset can be known at the initial asset
creation time, based on the referenced <code>universeKey</code> those wishing
to track any new asset issuance related to a given <code>genesisAssetID</code>
can watch the output on chain. Each time the output is spent indicates a new
minting event. As a result, clients are able to watch a select set of outputs
on-chain, one for each <code>genesisAssetID</code> they care about, effectively
using the blockchain to be notified each time the total amount of issued assets
changes.
====Asset Multiverses====
An Asset Multiverse is a Universe of Universes. Rather than just storing the
set of constituent assets (the set of <code>genesisOutpoints</code>), a
Multiverse commits to several root <code>assetIDs</code>, and may also commit
to proofs of asset transfers (including splits+merges). A Multiverse is
therefore effectively a commitment to every asset transfer that may have ever
happened. Importantly, one cannot prove that a Multiverse has complete
history, as a Multiverse can only commit to what it directly observed, or was
shown to it.
A Multiverse has the following structure:
* Similar to normal Taproot Asset commitments, the Multiverse itself contains two nested MS-SMT trees. The upper tree commits to the set of asset groups observed, with the inner tree committing to the transaction history of each of the asset groups.
* Upper tree structure:
** <code>key</code>: <code>asset_id</code> or <code>sha256(asset_key_family)</code>
** <code>value</code>: <code>asset_group_tree_root</code>
** <code>sum_value</code>: <code>asset_group_sum</code>
* Inner tree structure:
** <code>key</code>: an <code>sha256(outpoint || scriptKey)</code>, serialized in a <code>txid:vout</code> structure as we find in Bitcoin.
** <code>value</code>: <code>universe_proof_leaf</code>
** <code>sum_value</code>: the total amount of asset units issued by the proof leaf.
A Multiverse therefore commits to the set of known genesis IDs, and at a second
level the set of complete Universe trees for each watched asset.
With this structure, it's possible for the maintainers of the Multiverse to
also store subjectively complete history of the set of transfers. In addition,
this structure can be used to trace the set of transfers/lineage for a given
asset. Notice that we effectively commit to the set of all created outputs
associated with an asset, with the very first spend being the
<code>genesisOutpoint</code> spend. As a result, a full proof of an asset's
provenance is simply a series of keys stored at the lowest level of an SMT,
with verifies following the transfer from outpoint to outpoint within a tree.
Using the trait presented above, one can create a flat file that proves the
provenance of an asset simply by extracting select branches from a Multiverse
tree, and enumerating the set of keys one needs to assert for validation.
====Pocket Universes: Off-Chain Taproot Asset Transfer Compression====
All leaves within a Multiverse are themselves a commitment to an event that
happened on chain: A Taproot Asset transfer. Proofs for unique assets have a nice
property that they scale linearly in the number of asset transfers (you can't
split/merge so the same unit is being transferred to a differing set of
owners). Normal assets give a greater degree of flexibility, but scale worse
as a single asset held might actually be the merging of several Taproot Asset
UTXOs, thereby increasing proofs size as a function of the number of
splits/merges in an asset's history. Pocket Universes are an off-chain transfer
compression system that allows a consortium to stamp asset transfers that take
place in an "imaginary" universe.
To further reduce validation costs, verifiers can choose to only verify a
single input split all the way back to the genesis outpoint. This implements a
naive form of probabilistic validation, as the probability that each unverified
split is invalid decrease exponentially.
A Pocket Universe is similar to a commit chain. A single party, or a set of
parties, commits to a set of transfers within the main chain, which themselves
are anchored to an initial verifiable <code>genesisOutpoint</code>. A Pocket
Universe is therefore a scaling tool, as with a single new commitment on-chain,
an essentially unbounded amount of transfers can be timestamped within the
chain. Pocket Universes may be useful in cases where a party has issued
assets, that can only be used with the aide of the issuer, for example in-game
assets. Although the Pocket Universe relies on a federation, unilateral exist
is possible, given a proof of censorship event.
=====Pocket Universes Creation=====
In order to create a new empty Pocket Universe, the Pocket Universe
orchestrator first creates a new unique tapscript commitment within a segwit v1
output (Taproot) with the following structure:
* <code>tagged_hash("TapLeaf", leaf_version || pocket_universe_marker || pocket_universe_version || pocket_universe_hash)</code>
where:
* <code>pockt_universe_marker</code>: is the `sha256` hash of the ascii string "pocket universe".
* <code>pocket_universe_version</code>: is the version of the Universe commitment used.
* <code>pocket_universe_hash</code>: is the root hash of the Pocket Universe.
** The Pocket Universe is a normal Taproot Asset MS-SMT with the exception that the referenced previous outpoints of the <code>prev_id</code> for each asset only exists within the Taproot Asset Virtual Transaction Graph.
This serves to create a new empty Pocket Universe, as the
<code>pocket_universe_hash</code> will simply be the empty MS-SMT hash as no
contents are currently present in the Pocket Universe.
The outpoint that commits to the creation of a Pocket Universe is hence
referred to as the <code>pocketGenesisOutpoint</code>. A NUMS point derived
from this outpoint can then be computed as <code>M =
NUMS(pocketGenesisOutpoint)</code>. The traditional "hash and increment" approach to
generating NUMS points can be used, or any other variant. As performance isn't
a concern, the naive approach will likely be used in practice.
======Pocket Universe Dynamic Membership: Taproot Asset Virtual Transaction Graphs======
Within a Pocket Universe, rather than reference the on chain location of
committed assets, a new virtual transaction graph is created, which is rooted
at the <code>pocketGenesisOutpoint</code>. In order to join a Pocket Universe,
an asset must first be suspended. Once suspended, they can be added to the
Pocket Universe commitment, using the <code>pocketGenesisOutpoint</code> as a
''new'' minting/issuance event. Subsequent transfers will then reference the
''virtual transaction outpoint'' (as computed in the VM) as previous inputs.
Assets can also be minted ''directly'' into a Pocket Universe by the
orchestrator. To do this, the orchestrator creates a normal genesis asset, but
uses the normal all zero prev ID within the new Pocket Universe leaf.
======Joining a Pocket Universe======
In order to join a Pocket Universe, a party holding an asset `A` carries out
the following steps:
* In the same txn, send to the Pocket Universe NUMS key
* Create a new entry in the Pocket Universe for that output
* Within the new leaf, reference the pocket universe outpoint
Assets can be moved into a pocket Universe which is another commitment in the
main Tapscript tree by "sending" the set of outpoints to a special NUMS asset
key which is derived from the <code>genesisOutpoint</code> of the given asset.
Once the assets have been from the PoV of the base Universe, a new parallel
pocket Universe commitment can be created, which uses the ''new'' outpoint
created as a result of the above transfer transaction as the very first
spending input. From here, new transfers can be created, refreezing the
created outpoints of the virtual Taproot Asset VM validation transaction. The
result is an effective ''freezing'' of assets anchored in the main chain, which
then permits them to be batched and transferred in the maintained Pocket
Universe.
======Pocket Universe Transactions======
=======Leaving a Pocket Universe=======
====Asset Universe APIs & Federated Sync====
A Universe server communicates with clients and other Universe servers using
the standard Universe API. As a Universe is a tree-based structure, it lends
well to bisection based reconciliation protocols. A set of Universe servers can
peer with each other to form a Universe Federation. A users submit issuance and
transfer proofs to a sub-set of the Federation, gradual tree-based
reconciliation will serve to eventually synchronize the new state across the
set of federated Universe servers.
=====Universe gRPC API=====
The Universe gRPC API is implemented by the following standard gRPC service:
<source lang="python">
service Universe {
/*
AssetRoots queries for the known Universe roots associated with each known
asset. These roots represent the supply/audit state for each known asset.
*/
rpc AssetRoots (AssetRootRequest) returns (AssetRootResponse);
/*
QueryAssetRoots attempts to locate the current Universe root for a specific
asset. This asset can be identified by its asset ID or group key.
*/
rpc QueryAssetRoots (AssetRootQuery) returns (QueryRootResponse);
/*
AssetLeafKeys queries for the set of Universe keys associated with a given
asset_id or group_key. Each key takes the form: (outpoint, script_key),
where outpoint is an outpoint in the Bitcoin blockchain that anchors a
valid Taproot Asset commitment, and script_key is the script_key of the
asset within the Taproot Asset commitment for the given asset_id or
group_key.
*/
rpc AssetLeafKeys (ID) returns (AssetLeafKeyResponse);
/*
AssetLeaves queries for the set of asset leaves (the values in the Universe
MS-SMT tree) for a given asset_id or group_key. These represents either
asset issuance events (they have a genesis witness) or asset transfers that
took place on chain. The leaves contain a normal Taproot Asset asset proof,
as well as details for the asset.
*/
rpc AssetLeaves (ID) returns (AssetLeafResponse);
/*
QueryProof attempts to query for an issuance proof for a given asset based
on its UniverseKey. A UniverseKey is composed of the Universe ID
(asset_id/group_key) and also a leaf key (outpoint || script_key). If
found, then the issuance proof is returned that includes an inclusion proof
to the known Universe root, as well as a Taproot Asset state transition or
issuance proof for the said asset.
*/
rpc QueryProof (UniverseKey) returns (AssetProofResponse);
/*
InsertProof attempts to insert a new issuance proof into the
Universe tree specified by the UniverseKey. If valid, then the proof is
inserted into the database, with a new Universe root returned for the
updated asset_id/group_key.
*/
rpc InsertProof (AssetProof) returns (AssetProofResponse);
}
</source>
The service allows users to fetch the complete set of asset roots, fetch the
Universe root for a given asset, fetch the set of leaves/keys, and also attempt
to add a new issuance/transfer proof to the target Universe server.
The definition of each of the proto messages follows:
<source lang="python">
message AssetRootRequest {}
message MerkleSumNode {
// The MS-SMT root hash for the branch node.
bytes root_hash = 1;
// The root sum of the branch node. This is hashed to create the root_hash
// along with the left and right siblings. This value represents the total
// known supply of the asset.
int64 root_sum = 2;
}
message ID {
oneof id {
// The 32-byte asset ID.
bytes asset_id = 1;
// The 32-byte asset ID encoded as a hex string.
string asset_id_str = 2;
// The 32-byte asset group key.
bytes group_key = 3;
// The 32-byte asset group key encoded as hex string.
string group_key_str = 4;
}
}
message UniverseRoot {
ID id = 1;
// The merkle sum sparse merkle tree root associated with the above
// universe ID.
MerkleSumNode mssmt_root = 3;
}
message AssetRootResponse {
// A map of the set of known universe roots for each asset. The key in the
// map is the 32-byte asset_id or group key hash.
map<string, UniverseRoot> universe_roots = 1;
}
message AssetRootQuery {
// An ID value to uniquely identify a Universe root.
ID id = 1;
}
message QueryRootResponse {
// The asset root for the given asset ID or group key.
UniverseRoot asset_root = 1;
}
message Outpoint {
// The output as a hex encoded (and reversed!) string.
string hash_str = 1;
// The index of the output.
int32 index = 2;
}
message AssetKey {
// The outpoint of the asset key, either as a single hex encoded string, or
// an unrolled outpoint.
oneof outpoint {
string op_str = 1;
Outpoint op = 2;
}
// The script key of the asset.
oneof script_key {
bytes script_key_bytes = 3;
string script_key_str = 4;
}
}
message AssetLeafKeyResponse {
// The set of asset leaf keys for the given asset ID or group key.
repeated AssetKey asset_keys = 1;
}
message AssetLeaf {
// The asset included in the leaf.
taprpc.Asset asset = 1;
// TODO(roasbeef): only needed for display? can get from proof below ^
// The asset issuance proof, which proves that the asset specified above
// was issued properly.
bytes issuance_proof = 2;
}
message AssetLeafResponse {
// The set of asset leaves for the given asset ID or group key.
repeated AssetLeaf leaves = 1;
}
message UniverseKey {
// The ID of the asset to query for.
ID id = 1;
// The asset key to query for.
AssetKey leaf_key = 2;
}
message AssetProofResponse {
// The request original request for the issuance proof.
UniverseKey req = 1;
// The Universe root that includes this asset leaf.
UniverseRoot universe_root = 2;
// An inclusion proof for the asset leaf included below. The value is that
// issuance proof itself, with a sum value of the amount of the asset.
bytes universe_inclusion_proof = 3;
// The asset leaf itself, which includes the asset and the issuance proof.
AssetLeaf asset_leaf = 4;
}
message AssetProof {
// The ID of the asset to insert the proof for.
UniverseKey key = 1;
// The asset leaf to insert into the Universe tree.
AssetLeaf asset_leaf = 4;
}
enum UniverseSyncMode {
// A sync node that indicates that only new asset creation (minting) proofs
// should be synced.
SYNC_ISSUANCE_ONLY = 0;
// A syncing mode that indicates that all asset proofs should be synced.
// This includes normal transfers as well.
SYNC_FULL = 1;
}
message SyncTarget {
ID id = 1;
}
message SyncRequest {
string universe_host = 1;
// The sync mode. This determines what type of proofs are synced.
UniverseSyncMode sync_mode = 2;
// The set of assets to sync. If none are specified, then all assets are
// synced.
repeated SyncTarget sync_targets = 3;
}
message SyncedUniverse {
// The old Universe root for the synced asset.
UniverseRoot old_asset_root = 1;
// The new Universe root for the synced asset.
UniverseRoot new_asset_root = 2;
// The set of new asset leaves that were synced.
repeated AssetLeaf new_asset_leaves = 3;
}
message SyncResponse {
// The set of synced asset Universes.
repeated SyncedUniverse synced_universes = 1;
}
</source>
=====Universe REST API=====
In addition to a gRPC API, Universe servers also observe a matching REST API.
The REST API is the mirror of the gRPC API, and is structured to enable
familiar access to Universe information as one would expect in a block
explorer.
The following yaml describes the REST interface for Universe servers:
<source lang="yaml">
type: google.api.Service
config_version: 3
http:
rules:
- selector: universerpc.Universe.AssetRoots
get: "/v1/taproot-assets/universe/roots"
- selector: universerpc.Universe.QueryAssetRoots
get: "/v1/taproot-assets/universe/roots/asset-id/{id.asset_id_str}"
- selector: universerpc.Universe.QueryAssetRoots
get: "/v1/taproot-assets/universe/roots/group-key/{id.group_key_str}"
- selector: universerpc.Universe.AssetLeafKeys
get: "/v1/taproot-assets/universe/keys/asset-id/{asset_id_str}"
- selector: universerpc.Universe.AssetLeafKeys
get: "/v1/taproot-assets/universe/keys/group-key/{group_key_str}"
- selector: universerpc.Universe.AssetLeaves
get: "/v1/taproot-assets/universe/leaves/asset-id/{asset_id_str}"
- selector: universerpc.Universe.AssetLeaves
get: "/v1/taproot-assets/universe/leaves/group-key/{group_key_str}"
- selector: universerpc.Universe.QueryProof
get: "/v1/taproot-assets/universe/proofs/asset-id/{id.asset_id_str}/{leaf_key.op.hash_str}/{leaf_key.op.index}/{leaf_key.script_key_str}"
- selector: universerpc.Universe.QueryProof
get: "/v1/taproot-assets/universe/proofs/group-key/{id.group_key_str}/{leaf_key.op.hash_str}/{leaf_key.op.index}/{leaf_key.script_key_str}"
- selector: universerpc.Universe.InsertProof
post: "/v1/taproot-assets/universe/proofs/asset-id/{key.id.asset_id_str}/{key.leaf_key.op.hash_str}/{key.leaf_key.op.index}/{key.leaf_key.script_key_str}"
body: "*"
- selector: universerpc.Universe.InsertProof
post: "/v1/taproot-assets/universe/proofs/group-key/{key.id.group_key_str}/{key.leaf_key.op.hash_str}/{key.leaf_key.op.index}/{key.leaf_key.script_key_str}"
body: "*"
- selector: universerpc.Universe.SyncUniverse
post: "/v1/taproot-assets/universe/sync"
body: "*"
</source>
As an example, in order to query for any issued assets residing at the outpoint
`txid:vout`, for an assetiD `x` a user can hit the following endpoint:
<code>
/v1/taproot-assets/universe/keys/asset-id/x/txid/vout
</code>
=====Simple Universe Sync=====
As mentioned above, the tree based structure of a Universe server lends easily
to bisection based set reconciliation. In this case, the keys comprise the set
being synchronized.
In this section, we describe a simple linear algorithm for syncing a local
Universe, with a remote Universe server:
<source lang="python">
sync_with_universe(local_universe: UniverseServer, remote_universe: UniverseServer) -> None
// First fetch the set of roots from the local + remote server.
local_roots = local_universe.asset_roots()
remote_roots = remote_universe.asset_roots()
// If the local roots match the remote roots, then we're done.
if local_roots == remote_roots:
return
// Otherwise, for each root, we'll figure out which leaves we're missing.
for i, remote_root in range(remote_roots):
if remote_roots == local_roots[i]:
continue
remote_asset_keys = remote_universe.asset_leaf_keys(remote_root.id)
local_asset_keys = local_universe.asset_leaf_keys(local_root.id)
missing_keys = set(remote_asset_keys) - set(local_asset_keys)
for missing_key in range missing_keys:
missing_leaf = remote_universe.query_issuance_proofs(missing_key)
local_universe.insert_issuance_proof(missing_leaf)
</source>
A simple sync can be augmented by first recursively fetching the mismatched
sibling until an acceptable depth is reached before fetching all the leaves in
the terminal sub-tree. Each step serves to cut in half the total number of keys
that need to be sent in order to reconcile state.
==Test Vectors==
TBD
==Backwards Compatibility==
==Reference Implementation==
github.com/lightninglabs/taproot-assets/universe

288
bip-tap-vm.mediawiki Normal file
View file

@ -0,0 +1,288 @@
<pre>
BIP: ???
Layer: Applications
Title: Taproot Asset Script v1
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
</pre>
==Abstract==
This document describes the virtual machine execution environment used to
validate Taproot Asset transfers that utilize an
<code>asset_script_version</code> of 1.
The execution environment described in this document is a slight twist on
the taproot validation rules defined in BIPs 341 and 342. Given a Taproot Asset
one or more Taproot Asset leaves to be spent (inputs) and asset leaves to be
created, a "virtual" taproot Bitcoin transaction is created. This transaction
is a 1-input-1-output transaction that commits to the inputs and output set
using a merkle sum tree. With this mapping complete, validation takes place as
normal.
==Copyright==
This document is licensed under the 2-clause BSD license.
==Motivation==
The Taproot Asset overlay permits the usage of a nearly arbitrary virtual machine
for validation of transfers within the system. In order to reduce the scope of
the initial version of the protocol, we describe a way to leverage the existing
Bitcoin Script virtual machine, allowing us to inherit a baseline set of
expressibility, while allowing implementers re-use existing tools and
libraries.
==Design==
The Taproot Asset <code>asset_script_version</code> 1 maps a Taproot Asset input
and output set to a "virtual" Bitcoin transaction.
The input and output sets are committed to within a single 1-input-1-output
transaction using a normal merkle sum tree
(TODO(roasbeef): non-inclusion useful at all here??).
Via the merkle-sum
invariant of the augmented merkle tree, a validator is able to enforce
non-inflation of assets by asserting that the committed input sum is ''equal''
to the committed output sum. Once this invariant is verified, execution resumes
as normal using the BIP 341+342 validation rules, with additional pre-execution
checks that may fail validation early.
===Specification===
A single 1-input-1-output transaction is used to compress the Taproot Asset
state transition state into a constant size transaction. Given a Taproot Asset
commitment (which lives in a taproot output), and its valid opening, the set
the previous asset ID are compressed into a single input, and the present
<code>split_commitment</code> is used to compress the output state.
State transition validation may take one or multiple asset leaves within a
single transaction (with the leaves living in different outputs). When a single
leaf is present, no splits occurred in the state transition, or the asset is a
collectible. When two or more leaves are specified, then all but one of the
leaves were splits resulting from a split event at the Taproot Asset layer. In
this case, the split commitment proof, as well as the validity of the state
transition creating the splits are validated.
====Mapping Inputs====
Input mapping is only executed for state transitions that specify
<code>prev_asset_witnesses</code>.
Given a set of inputs, each identified by a <code>prev_asset_id</code>, the
input commitment (which is used as the previous output) is constructed as
follows:
# Initialize a new empty MS-SMT tree as specified in [[./bip-tap-ms-smt.mediawiki|bip-tap-ms-smt]].
# For each Taproot Asset input ''c_i'', identified in the <code>prev_asset_witnesses</code> field:
## If the asset input has a <code>split_commitment</code> in the witness, that needs to be removed before the serialization step.
## Serialize the referenced previous asset leaf (identified by <code>prev_outpoint || asset_id || asset_script_hash</code>) in TLV format.
## Insert this leaf into the MS-SMT tree, with a key of the <code>prev_id_identifier</code>, a value of the serialized leaf, and sum value of the asset amount contained in the leaf.
# Obtain the root hash <code>input_root</code> and sum value <code>input_asset_sum</code> resulting from the tree creation and root digest computation.
# Let the hash of the serialized 36-byte MS-SMT root be the sole previous outpoint (the txid) of the virtual execution transaction.
With the above routine, we map the input set into a MS-SMT tree, which also
commits to the total amount being spent of any given asset. During
verification, as there may be multiple input witnesses, during validation, the
<code>asset_witness</code> for each input is used as the initial witness stack.
Notice that we don't map the <code>relative_lock_time</code> field here within
this unified input commitment. Instead we'll map this during the
verification/signing process, which enables the existence of per-input relative
and absolute lock time.
The following algorithm implements the input mapping required for full state
transition verification:
<source lang="python">
make_virtual_input(prev_inputs: map[PrevOut]TaprootAssetLeaf) -> (MerkleSumRoot, TxIn):
input_smt = new_ms_smt()
for prev_out, taproot_asset_leaf in prev_inputs:
leaf_bytes = taproot_asset_leaf.serialize_tlv()
input_smt.insert(key=prev_out, value=leaf_bytes, sum_value=taproot_asset_leaf.amt)
input_root = input_smt.root()
virtual_txid = sha256(input_root.hash || input_root.sum_value)
# We only only bind the virtual txid here. Below we'll modify the input
# index based on the ordering of this SMT.
return input_root, NewTxIn(NewOutPoint(txid=virtual_txid), nil)
</source>
====Mapping Outputs====
Output mapping is only executed for state transitions that specify
<code>prev_asset_witnesses</code>.
Given a Taproot Asset output, and any associated outputs contained within its
<code>split_commitment_root</code>, the output commitment is constructed as
follows:
# For normal asset transfers:
## Let the output value be the sum of all the <code>amt</code> fields on the top level as well as the split commitment cohort set, in other words the last 4-bytes of the <code>split_commitment_root</code>.
## Let the output script be the first 32-bytes of the <code>split_commitment_root</code> value converted to a segwit v1 witness program (taproot).
# For collectible asset transfers
## Let the output value be exactly ''1'' (as each TLV leaf related to a collectible can only ever transfer that same collectible to another leaf).
## Let the output script be the first 32-bytes of an MS-SMT tree with a single element of the serialized TLV leaf of the collectible.
### The key for this single value is <code>sha256(asset_key_family || asset_id || asset_script_key)</code>. If a <code>asset_key_family</code> field isn't specified, then 32-bytes of zeroes should be used in place.
The following algorithm implements the output mapping required for full state
transition verification:
<source lang="python">
make_virtual_txout(leaf: TaprootAssetLeaf) -> (MerkleSumRoot, TxOut):
match leaf.asset_type:
case Normal:
tx_out = NewTxOut(
pk_script=[OP_1 OP_DATA_32 leaf.split_commitment_root.hash],
value=leaf.split_commitment_root.sum_value,
)
return leaf.split_commitment_root, tx_out
case Collectible:
output_smt = new_ms_smt()
output_smt.insert(
key=sha256(leaf.asset_key_family || leaf.asset_id || leaf.asset_script_key)
value=leaf.serialize_tlv(),
sum_value=1,
)
witness_program = output_smt.root_hash()
tx_out = NewTxOut(
pk_script=[OP_1 OP_DATA_32 witness_program],
value=1,
)
return output_smt.root, tx_out
</source>
====Validating a State Transition====
If a state transition specifies a <code>prev_asset_witnesses</code> field, then
once the set of inputs and outputs have been mapped to our virtual Bitcoin
transaction (creating a v2 Bitcoin transaction with a single input and output),
validation proceeds as normal according to BIP 341+342 with the following
modifications:
# If the <code>input_asset_sum</code> is not exactly equal to the <code>output_asset_sum</code> validation MUST fail.
# For each <code>prev_input</code> within the set of referenced <code>prev_asset_witnesses</code>:
## If the <code>asset_type</code> of the referenced input leaf doesn't map the <code>asset_type</code> of the Taproot Asset leaf spending the input, validation MUST fail.
## Construct a single-input-single-output Bitcoin transaction based on the input and output mapping above.
### The prev out input index should be the lexicographical index of the <code>prev_id_identifier</code> field for each input.
### The previous public key script should be the <code>asset_script_hash</code> for the current previous input, mapped to a v1 segwit witness program (taproot).
### The input value for each included input is to be the <code>amt</code> field of the previous Taproot Asset output being spent.
### Set the sequence number to the <code>relative_lock_time</code> field of the input, if it exists.
## Set the lock time of the transaction as the <code>lock_time</code> of the input TLV leaf being validated, if it exists.
## All signatures included in the witness MUST be exactly 64-bytes in length, which triggers <code>SIGHASH_DEFAULT</code> evaluation.
## If the <code>prev_asset_id</code> is blank, then ALL witnesses MUST be blank as well and the <code>prev_outpoint</code> values as well. In this case, verification succeeds as this is only a creation/minting transaction.
## If the <code>asset_id</code> value is NOT the same for each Taproot Asset input and output, validation MUST fail.
### Alternatively, assert that each input and output references the same <code>asset_family_key</code> field.
## Perform external lock time and relative lock time validation:
### If a <code>relative_lock_time</code> field exists, if the input age of the referenced TLV leaf is less than <code>relative_lock_time</code> validation MUST fail.
### If a <code>lock_time</code> field exists, if the block height of the block that includes the transaction is less than <code>lock_time</code> validation MUST fail.
## Validate the transaction according to the BIP 341+342 rules.
We explicitly implement lock time semantics at this level, as the sequence and
lock time fields in the context of Bitcoin itself are validated from the PoV of
connecting a new block to the end of the main chain.
Otherwise, if a state transition only specifies a <code>split_commitment_proof</code>, then:
# If the Taproot Asset output to be validated only specifies a <code>split_commitment_proof</code> and no explicit inputs, then a valid inclusion proof for the output MUST be presented and valid.
## If the proof is invalid, then validation MUST fail.
# Given the "parent" split, execute the input+output mapping and verify the state transition using the logic above.
The following algorithm implements verification for top level Taproot Asset
leaves, as well leaves created via split commitments:
<source lang="python">
verify_taproot_asset_state_transition(leaf: TaprootAssetLeaf, leaf_split: TaprootAssetLeaf) -> bool
if is_valid_issuance_txn(leaf):
return true
if leaf_split is not None:
if leaf is None:
return false
if !verify_split_commitment(leaf.split_commitment_root,
leaf_split.split_commitment_proof):
return false
input_smt, tx_in = make_virtual_input(leaf.prev_inputs)
output_smt, tx_out = make_virtual_txout(leaf)
if input_smt.sum_value != output_smt.sum_value:
return false
virtual_tx_template = NewTx([tx_in], [tx_out])
for input in range leaf.prev_inputs:
if input.asset_type != leaf.asset_type:
return false
match input.asset_id:
case AssetID:
if input.asset_id != leaf.asset_id:
return false
case KeyFamily:
if input.asset_key_family != leaf.asset_key_family:
return false
virtual_tx = virtual_tx_template.clone()
if !parse_valid_schnorr_sigs(input.asset_witness):
return false
virtual_tx.tx_in[0].witness = input.asset_witness
virtual_tx.tx_in[0].prev_out.index = input_smt.leaf_index_of(input)
prev_pk_script = OP_1 OP_DATA_32 input.asset_script_key
input_value = input.amt
if input.relative_lock_time != 0:
virtual_tx.tx_in[0].sequence = relative_lock_time
input_age = conf_input_age(input)
if num_confs(input) < input_age:
return false
if input.lock_time != 0:
virtual_tx.lock_time = leaf.lock_time
block_height = env.block_height()
if block_height < virtual_tx.lock_time:
return false
vm = new_script_vm(
prev_pk_script=prev_pk_script, tx=virtual_tx, input_index=0,
input_amt=input_value,
)
if !vm.Execute():
return false
return true
</source>
==Test Vectors==
Test vectors for [[Validating a State Transition]] can be found here:
* [[bip-tap-vm/vm_validation_generated.json|VM validation test vectors]]
* [[bip-tap-vm/vm_validation_generated_error_cases.json|VM validation error test vectors]]
The test vectors are automatically generated by
[https://github.com/lightninglabs/taproot-assets/tree/main/vm unit tests in
the Taproot Assets GitHub repository].
==Backwards Compatibility==
==Reference Implementation==
github.com/lightninglabs/taproot-assets/tree/main/vm

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1117
bip-tap.mediawiki Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
{
"valid_test_cases": [
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"expected": "b87da731321c9e90a2f3d525cf81a2f503e04ea49543692951e6b88752a0d72d",
"comment": "empty prev ID"
},
{
"prev_id": {
"out_point": "00000000000000000000000000000000000000000000000000000000aa998877:123",
"asset_id": "0102030400000000000000000000000000000000000000000000000000000000",
"script_key": "020304050000000000000000000000000000000000000000000000000000000000"
},
"expected": "77493dcf8c7e6c1f214824409b2468afe8e4e5faa47e6ae87ddb60226ad4edde",
"comment": "dummy value ID"
},
{
"prev_id": {
"out_point": "c8ca462e6247b1c7d67f9e2b5e371fc9303c3c3e6d690e8fb4a6bb5ca5b78104:354062834",
"asset_id": "560982cea2defb7795dda938422b4d7ae5462e64cde32fc68ced4f503f8a5af7",
"script_key": "03c50bfc65dfb20e9b9c1c6d8b435ef91f41eb86434576823eeaf3a69fa7e1fc78"
},
"expected": "a76bc68f430c78cfdad6d72abf143de10c8b679842fe00736072361b52ad426c",
"comment": "random value ID"
}
]
}

View file

@ -0,0 +1,45 @@
{
"error_test_cases": [
{
"asset": {},
"error": "missing genesis fields"
},
{
"asset": {
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000"
},
"error": "missing script key"
},
{
"asset": {
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "0000000000000000000000000000000000000000000000000000000000000000"
},
"error": "invalid script key length",
"comment": "script key must be 33 bytes (compressed)"
},
{
"asset": {
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
"group_key": {}
},
"error": "missing group key"
},
{
"asset": {
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
"group_key": {
"group_key": "0000000000000000000000000000000000000000000000000000000000000000"
}
},
"error": "invalid group key length",
"comment": "group key must be 33 bytes (compressed)"
}
]
}

View file

@ -0,0 +1,142 @@
{
"valid_test_cases": [
{
"asset": {
"version": 1,
"genesis_first_prev_out": "0101010101010101010101010101010101010101010101010101010101010101:1",
"genesis_tag": "asset",
"genesis_meta_hash": "0102030000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 1,
"genesis_type": 1,
"amount": 1,
"lock_time": 1337,
"relative_lock_time": 6,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0101010101010101010101010101010101010101010101010101010101010101:1",
"asset_id": "0101010101010101010101010101010101010101010101010101010101010101",
"script_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f"
},
"tx_witness": null,
"split_commitment": {
"proof": "000197efb64d447880bacc7070f428a1310b2592d155b752da382934d4bd0fbb419a000000000000000affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"root_asset": {
"version": 1,
"genesis_first_prev_out": "0101010101010101010101010101010101010101010101010101010101010101:1",
"genesis_tag": "asset",
"genesis_meta_hash": "0102030000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 1,
"genesis_type": 1,
"amount": 1,
"lock_time": 1337,
"relative_lock_time": 6,
"prev_witnesses": [
{
"prev_id": {
"out_point": "0202020202020202020202020202020202020202020202020202020202020202:2",
"asset_id": "0202020202020202020202020202020202020202020202020202020202020202",
"script_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f"
},
"tx_witness": [
"02",
"02"
],
"split_commitment": null
}
],
"split_commitment_root": {
"hash": "0101010101010101010101010101010101010101010101010101010101010101",
"sum": "1337"
},
"script_version": 1,
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"group_key": {
"group_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"group_key_sig": "e907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0"
}
}
}
}
],
"split_commitment_root": null,
"script_version": 1,
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"group_key": {
"group_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"group_key_sig": "e907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0"
}
},
"expected": "000101014f010101010101010101010101010101010101010101010101010101010101010100000001056173736574010203000000000000000000000000000000000000000000000000000000000000000001010201010301010403fd053905010606fd024501fd02410065010101010101010101010101010101010101010101010101010101010101010100000001010101010101010101010101010101010101010101010101010101010101010103a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f02fd01d64a000197efb64d447880bacc7070f428a1310b2592d155b752da382934d4bd0fbb419a000000000000000affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd0188000101014f010101010101010101010101010101010101010101010101010101010101010100000001056173736574010203000000000000000000000000000000000000000000000000000000000000000001010201010301010403fd05390501060670016e0065020202020202020202020202020202020202020202020202020202020202020200000002020202020202020202020202020202020202020202020202020202020202020203a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0105020102010207280101010101010101010101010101010101010101010101010101010101010101000000000000053908020001092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0a6103a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078fe907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c008020001092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0a6103a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078fe907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0",
"comment": "random split asset with root asset"
},
{
"asset": {
"version": 2,
"genesis_first_prev_out": "0202020202020202020202020202020202020202020202020202020202020202:2",
"genesis_tag": "asset",
"genesis_meta_hash": "0102030000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 2,
"genesis_type": 2,
"amount": 2,
"lock_time": 1337,
"relative_lock_time": 6,
"prev_witnesses": [
{
"prev_id": null,
"tx_witness": null,
"split_commitment": null
},
{
"prev_id": {
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
},
"tx_witness": null,
"split_commitment": null
},
{
"prev_id": {
"out_point": "0202020202020202020202020202020202020202020202020202020202020202:2",
"asset_id": "0202020202020202020202020202020202020202020202020202020202020202",
"script_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f"
},
"tx_witness": [
"02",
"02"
],
"split_commitment": null
}
],
"split_commitment_root": null,
"script_version": 2,
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"group_key": null
},
"expected": "000102014f020202020202020202020202020202020202020202020202020202020202020200000002056173736574010203000000000000000000000000000000000000000000000000000000000000000002020201020301020403fd053905010606d9030067006500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e0065020202020202020202020202020202020202020202020202020202020202020200000002020202020202020202020202020202020202020202020202020202020202020203a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0105020102010208020002092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"comment": "random asset with multiple previous witnesses"
},
{
"asset": {
"version": 0,
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
"genesis_tag": "",
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"genesis_output_index": 0,
"genesis_type": 0,
"amount": 0,
"lock_time": 0,
"relative_lock_time": 0,
"prev_witnesses": null,
"split_commitment_root": null,
"script_version": 0,
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"group_key": null
},
"expected": "000100014a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002010003010008020000092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
"comment": "minimal asset"
}
],
"error_test_cases": null
}