Merkle-Sum Sparse Merkle tree and Taproot

Taproot Assets are registered on the Bitcoin blockchain in the form of hashed metadata attached to a transaction output. This chapter details where and how it is stored.

Everything starts with a UTXO

Taproot allows a new way to create a conditions for a transaction output. You can now lock the UTXO with the hash of a Taproot script tree (a merkle tree). This is how it looks like that:

graph TD %% ============================================================================================================= %% Transaction INPUT0["Input 0"] INPUT1["Input 1"] OUTPUT0["Output 0"] OUTPUT1["Output 1 (Taproot)"] OUTPUT2["Output 2"] TRANSACTION["Bitcoin transaction"] INPUT0 --> TRANSACTION INPUT1 --> TRANSACTION TRANSACTION --> OUTPUT0 TRANSACTION --> OUTPUT1 TRANSACTION --> OUTPUT2 %% ============================================================================================================= %% ============================================================================================================= %% Taproot OUTPUT1 --> TAPROOT_ROOT_HASH["Taproot root hash"] TAPROOT_ROOT_HASH --> HASH12["Hash(1&2)"] TAPROOT_ROOT_HASH --> HASH3["Hash(3)"] HASH12 --> HASH1["Hash(1)"] HASH12 --> HASH2["Hash(2)"] HASH1 --> SCRIPT1["Script 1
Requires alice & bob's signatures"] HASH2 --> SCRIPT2["Script 2
Requires alice's signature"] HASH3 --> SCRIPT3["Script 3
Requires bob's signatures & time lock"]

When someone will want to spend it, he will only have to provide a single leaf’s script, a merkle proof to show inclusion in the tree, and fulfillment of the spending conditions of the script. To be more clear, you could, for example, provides the script n°2 and the proof that this script is included in the tree having the hash stored in the UTXO.

Where is our Merkle-Sum Sparse Merkle tree?

As we’ve seen in the previous chapter, our Taproot Assets are stored in a Merkle-Sum Sparse Merkle tree. The hash of our Taproot Assets tree will be stored in one leaf of our Taproot script as you can see here:

graph TD TAPROOT_ROOT_HASH["Taproot root hash"] TAPROOT_ROOT_HASH --> HASH12["Hash(1&2)"] TAPROOT_ROOT_HASH --> HASH3["Hash(3)"] HASH12 --> HASH1["Hash(1)"] HASH12 --> HASH2["Hash(2)"] HASH1 --> SCRIPT1["Script 1
Requires alice & bob's signatures"] HASH2 --> SCRIPT2["Script 2
Requires alice's signature"] HASH3 --> SCRIPT3["Taproot Assets Count (300)
Taproot Assets Root Hash: Hash (00, 01, null, 11)
"] %% ============================================================================================================= %% Taproot Assets SCRIPT3 -.-> HASH00-01["123, Hash (00, 01)"] SCRIPT3 -.-> HASH10-11["177, Hash (null, 11)"] HASH00-01 --> HASH01["113, Hash (00)"] HASH00-01 --> HASH02["10, Hash (01)"] HASH10-11 --> HASH03["0, Hash (null)"] HASH10-11 --> HASH04["177, Hash (11)"] HASH01 --> POSITION0["Position 1
Amount: 113 USDB"] HASH02 --> POSITION1["Position 2
Amount: 10 USDB"] HASH03 --> POSITION2["Position 3
Amount: 0 null"] HASH04 --> POSITION3["Position 4
Amount: 177 USDB"]

Instead of having script 3, we stored there our Taproot Assets root. As a Taproot transaction look similar to any other bitcoin transaction, the nodes won’t even know that Taproot Assets exists.