Skip to content

Commit

Permalink
Specify Merkle Tree Proof Computation
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippGackstatter committed Oct 25, 2023
1 parent f76f9c2 commit 145d0f8
Showing 1 changed file with 330 additions and 5 deletions.
335 changes: 330 additions & 5 deletions tips/TIP-0045/tip-0045.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,185 @@ The motivation of these changes is to adjust the transaction and its validation
2.0. Validation rules must now consider the Mana decay factor and the possibility of Mana allotment in the transaction
to a Block Issuance Credits account.

# Building Blocks

## Merkle Tree

A [merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) is a tree data structure that allows for efficient proofs of
inclusion.

A merkle tree proof is serialized as one of three possible schemas: A tree node, the hash of a leaf or the hash of the
value for which the proof is computed.

### Node

<details>
<summary>Node</summary>
<blockquote>Contains the hash of the value for which the proof is being computed.</blockquote>
</details>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Merkle Tree Component Type</td>
<td>uint8</td>
<td>Set to <strong>value 0</strong> to denote a <i>Node</i>.</td>
</tr>
<tr>
<td valign="top">Left <code>oneOf</code></td>
<td colspan="2">
<details>
<summary>Node</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#node'>TIP-45 (Node)</a>.</blockquote>
</details>
<details>
<summary>Leaf Hash</summary>
<blockquote>Contains the hash of a leaf in the tree. Defined in <a href='../TIP-0045/tip-0045.md#leaf-hash'>TIP-45 (Leaf Hash)</a>.</blockquote>
</details>
<details>
<summary>Value Hash</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#value-hash'>TIP-45 (Value Hash)</a>.</blockquote>
</details>
</td>
</tr>
<tr>
<td valign="top">Right <code>oneOf</code></td>
<td colspan="2">
<details>
<summary>Node</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#node'>TIP-45 (Node)</a>.</blockquote>
</details>
<details>
<summary>Leaf Hash</summary>
<blockquote>Contains the hash of a leaf in the tree. Defined in <a href='../TIP-0045/tip-0045.md#leaf-hash'>TIP-45 (Leaf Hash)</a>.</blockquote>
</details>
<details>
<summary>Value Hash</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#value-hash'>TIP-45 (Value Hash)</a>.</blockquote>
</details>
</td>
</tr>
</table>

### Leaf Hash

<details>
<summary>Leaf Hash</summary>
<blockquote>Contains the hash of a leaf in the tree.</blockquote>
</details>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Merkle Tree Component Type</td>
<td>uint8</td>
<td>Set to <strong>value 1</strong> to denote a <i>Leaf Hash</i>.</td>
</tr>
<tr>
<td>Hash</td>
<td>(uint8)ByteArray</td>
<td>The hash of the leaf.</td>
</tr>
</table>

### Value Hash

<details>
<summary>Value Hash</summary>
<blockquote>Contains the hash of the value for which the proof is being computed.</blockquote>
</details>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Merkle Tree Component Type</td>
<td>uint8</td>
<td>Set to <strong>value 2</strong> to denote a <i>Value Hash</i>.</td>
</tr>
<tr>
<td>Hash</td>
<td>(uint8)ByteArray</td>
<td>The hash of the value.</td>
</tr>
</table>

### Proof Computation

A **merkle proof** is computed as follows:

- Preliminary Definitions:
- Let `Leaves` be an array of serialized values, representing the leaves of the tree and `Leaves Len` the length of
that array.
- Let `Leaves[i]` denote the `i`-th element in the `Leaves` array.
- Let `Leaves[Start:End]` denote the subslice of `Leaves` from `Start` (inclusive) to `End` (exclusive).
- Let `Largest Power Of Two(n)` be a procedure that returns the largest power of two less than `n`.
- BLAKE2b-256 is used as the hash function.
- Let `Hash Leaf(Bytes)` be a procedure that produces the hash of the given byte array consisting of these values in
their displayed order:
- the leaf domain-separation prefix with value `0` of type `uint8`,
- and `Bytes`.
- Let `Hash Node(Left Bytes, Right Bytes)` be a procedure that produces the hash of the given byte arrays consisting of
these values in their displayed order:
- the node domain-separation prefix with value `1` of type `uint8`,
- and `Left Bytes`,
- and `Right Bytes`.
- Let `Hash Subtree(Leaves)` be a procedure that produces the hash of a sub-tree in the following way:
- If `Leaves Len == 0` return the hash of the empty string.
- If `Leaves Len == 1` return a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`.
- Otherwise, compute `Split` as `Largest Power Of Two(Leaves Len)`:
- Let `Left` be the result of `Hash Subtree(Leaves[0:Split])`.
- Let `Right` be the result of `Hash Subtree(Leaves[Split:Leaves Len])`.
- Return `Hash Node(Left, Right)`
- Let `Compute Proof(Leaves, Index)` be the procedure that computes the proof for the leaf at index `Index`, defined as
follows:
- If `Leaves Len == 0` return an error, since at least one item is required to compute a proof.
- If `Leaves Len == 1` return a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`.
- If `Leaves Len == 2`:
- If `Index == 0` return a `Node` with:
- `Left` set to a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`.
- `Right` set to a `Leaf Hash` with its `Hash` field set to `Hash Leaf(Leaves[1])`.
- If `Index == 1` return a `Node` with:
- `Left` set to a `Leaf Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`.
- `Right` set to a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[1])`.
- Otherwise, compute `Split` as `Largest Power Of Two(Leaves Len)`:
- If `Index < Split` return a `Node` with:
- `Left` set to the result of `Compute Proof(Leaves[0:Split], Index)`.
- `Right` set to a `Leaf Hash` with its `Hash` field set to `Hash Subtree(Leaves[Split:Leaves Len])`.
- Otherwise return a `Node` with:
- `Left` set to a `Leaf Hash` with its `Hash` field set to `Hash Subtree(Leaves[0:Split])`.
- `Right` set to the result of `Compute Proof(Leaves[Split:Leaves Len], Index)`.

### Root Computation

The **merkle root** is the result of `Hash Subtree(Leaves)`.

# Detailed design

## UTXO
Expand Down Expand Up @@ -406,12 +585,158 @@ that the output and its ID match which in turn renders the Inputs Commitment unn

More generally, this setup is also useful to prove that a given transaction produced an output with a certain state.

Such an Output ID Proof is a [merkle proof](https://en.wikipedia.org/wiki/Merkle_tree), with the array of the serialized
`Outputs` as the leaves of the tree. A proof is generated for a specific index in the array.
Such an Output ID Proof is a [merkle proof](#merkle-tree), with the array of the serialized `Outputs` as the `Leaves` of
the tree.

A proof is serialized as follows:

TODO
<details>
<summary>Output ID Proof</summary>
<blockquote>A merkle proof that allows for cryptographic verification that an Output ID belongs to a given Output.</blockquote>
</details>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Slot</td>
<td>uint32</td>
<td>The slot in which the Output was created.</td>
</tr>
<tr>
<td>Output Index</td>
<td>uint16</td>
<td>The index of the output in the transaction.</td>
</tr>
<tr>
<td>Transaction Commitment</td>
<td>ByteArray[32]</td>
<td>The commitment to the transaction.</td>
</tr>
<tr>
<td valign="top">Output Commitment Proof <code>oneOf</code></td>
<td colspan="2">
<details>
<summary>Node</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#node'>TIP-45 (Node)</a>.</blockquote>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Merkle Tree Component Type</td>
<td>uint8</td>
<td>Set to <strong>value 0</strong> to denote a <i>Node</i>.</td>
</tr>
<tr>
<td valign="top">Left <code>oneOf</code></td>
<td colspan="2">
<details>
<summary>Node</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#node'>TIP-45 (Node)</a>.</blockquote>
</details>
<details>
<summary>Leaf Hash</summary>
<blockquote>Contains the hash of a leaf in the tree. Defined in <a href='../TIP-0045/tip-0045.md#leaf-hash'>TIP-45 (Leaf Hash)</a>.</blockquote>
</details>
<details>
<summary>Value Hash</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#value-hash'>TIP-45 (Value Hash)</a>.</blockquote>
</details>
</td>
</tr>
<tr>
<td valign="top">Right <code>oneOf</code></td>
<td colspan="2">
<details>
<summary>Node</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#node'>TIP-45 (Node)</a>.</blockquote>
</details>
<details>
<summary>Leaf Hash</summary>
<blockquote>Contains the hash of a leaf in the tree. Defined in <a href='../TIP-0045/tip-0045.md#leaf-hash'>TIP-45 (Leaf Hash)</a>.</blockquote>
</details>
<details>
<summary>Value Hash</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#value-hash'>TIP-45 (Value Hash)</a>.</blockquote>
</details>
</td>
</tr>
</table>
</details>
<details>
<summary>Leaf Hash</summary>
<blockquote>Contains the hash of a leaf in the tree. Defined in <a href='../TIP-0045/tip-0045.md#leaf-hash'>TIP-45 (Leaf Hash)</a>.</blockquote>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Merkle Tree Component Type</td>
<td>uint8</td>
<td>Set to <strong>value 1</strong> to denote a <i>Leaf Hash</i>.</td>
</tr>
<tr>
<td>Hash</td>
<td>(uint8)ByteArray</td>
<td>The hash of the leaf.</td>
</tr>
</table>
</details>
<details>
<summary>Value Hash</summary>
<blockquote>Contains the hash of the value for which the proof is being computed. Defined in <a href='../TIP-0045/tip-0045.md#value-hash'>TIP-45 (Value Hash)</a>.</blockquote>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Merkle Tree Component Type</td>
<td>uint8</td>
<td>Set to <strong>value 2</strong> to denote a <i>Value Hash</i>.</td>
</tr>
<tr>
<td>Hash</td>
<td>(uint8)ByteArray</td>
<td>The hash of the value.</td>
</tr>
</table>
</details>
</td>
</tr>
</table>

### Transaction ID

Expand All @@ -420,8 +745,8 @@ A Transaction ID consists of two commitments, the _Transaction Commitment_ and t

- Let `Transaction Bytes` be the concatenated serialization of the fields from `Network ID` to `Payload`.
- Let `Transaction Commitment` be the BLAKE2b-256 hash of `Transaction Bytes`.
- Let `Output Commitment` be the root of the merkle tree over the `Outputs`. See [Output ID Proof](#output-id-proof) for
more details.
- Let `Output Commitment` be the [merkle root](#root-computation) over the merkle tree with the serialized `Outputs` as
its `Leaves`.
- Let `ID` be the BLAKE2b-256 of the concatenation of `Transaction Commitment` and `Output Commitment`.
- Construct the `Transaction ID` as the concatenation of the `ID` and the little-endian encoded `Creation Slot`.

Expand Down

0 comments on commit 145d0f8

Please sign in to comment.