https://github.com/alilloig/merkle-mountain-range-contracts
A collection of Merkle Mountain Range implementations for different blockchains
https://github.com/alilloig/merkle-mountain-range-contracts
blockchain cadence move-language smart-contracts
Last synced: 6 months ago
JSON representation
A collection of Merkle Mountain Range implementations for different blockchains
- Host: GitHub
- URL: https://github.com/alilloig/merkle-mountain-range-contracts
- Owner: alilloig
- Created: 2025-03-17T18:25:57.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2025-04-01T15:54:39.000Z (6 months ago)
- Last Synced: 2025-04-01T16:26:14.110Z (6 months ago)
- Topics: blockchain, cadence, move-language, smart-contracts
- Language: Move
- Homepage:
- Size: 46.9 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Merkle Mountain Range
## Introduction
A Merkle Mountain Range (MMR) is a data structure that extends the concept of a Merkle tree to allow for efficient appending of new elements and efficient proof generation. MMRs are particularly useful in scenarios where on-chain data updates are necessary.
### Properties and Applications
1. **Append-Only**: Efficiently supports adding new elements
2. **Compact Proofs**: Proof size is logarithmic in the number of elements
3. **Verification Efficiency**: Proofs can be verified quickly
4. **No Rebalancing**: Unlike traditional Merkle trees, MMRs don't require rebalancing## Basic Structure and Formation
In an MMR, nodes are arranged in a series of perfect binary trees (mountains) of decreasing height from left to right.
When a piece of data is to be added to the MMR it gets hashed creating a node that, using 1-based numbering and starting from the left, is added to the MMR. Whenever a left node gains a sibling, a parent node is created by hashing both children together, following sequential numbering. If the newly created parent node already has a right sibling at the same level, another parent node will be created for them, and so on.### Visualizing an MMR
Let's look at an MMR with 13 leaves (represented by positions 1, 2, 4, 5, 8, 9, 11, 12, 16, 17, 19, 20 and 23):
```
15
/ \
/ \
/ \
7 14 22
/ \ / \ / \
/ \ / \ / \
3 6 10 13 18 21
/ \ / \ / \ / \ / \ / \
1 2 4 5 8 9 11 12 16 17 19 20 23```
## Key concepts
Clarifying a few key terms is essential for understanding MMRs and avoiding confusion during implementation, which also improves code readability.
### Position
The number assigned to each node is called its position. This numbering will be 1-based rather than 0-based as it will be on other data structs.
While this may seem arbitrary, it is crucial for the mathematical properties of MMRs, enabling operations such as calculating a node's height.
It is important not to confuse this position with the order in which data was added to the MMR—sometimes referred to as the "leaf number"—as this is not relevant to MMR implementation.### Height
Each node has an associated height depending on which level of the MMR they are placed.
In this implementation height is numbered 1-based as positions are.
Based on the height of a given node, we can differentiate node types.#### Node Types
A node on the first level, height 1, will always be a **Leaf Node**.
These nodes contain the hash of the stored data along with the position of the leaf within the structure.
The top nodes of each perfect binary tree (mountain) will be **Peak Nodes**. In our previous example peaks will be nodes 15, 22 and 23.
Intermediate nodes do not require a specific term, as their height is only relevant for traversal calculations within the MMR.
Given a node position, its height can be calculated by iterating through the binary tree it is part of.### Size
The total amount of nodes that form the MMR, including leaves and peaks, is referred as the MMR size.
### Root
The unique identifier of a MMR at a certain point of its life, obtained by hashing together all the peaks (also known as bagging peaks) preceded by its size.
## MMR Proofs
The minimum necessary set of information from the MMR needed for checking if a piece of data was included on it.
All these elements correspond to a specific point in the MMR's lifecycle, meaning that if a proof is generated for the same data at a later time, after more leaves have been added, the proof will differ.- Position of the leaf where the data was included.
- Local tree path hashes.
- Left hand sided peaks.
- Right hand sided peaks.
- MMR's root hash and size.Taking our initial MMR example if we want to generate a proof for the node 16, we will pack in a structure the following information:
```pseudocode
struct Proof {
int position = 16
[hash] localTreePathHashes = [h(n17),h(n21)]
[hash] lhsPeaksHashes = [h(n15)]
[hash] rhsPeaksHashes = [h(n23)]
hash mmrRoot = h(23,h(n15),h(n22),h(n23))
int mmrSize = 23
}
```Understanding the concept of local tree path hashes is crucial, as they are the key element in proof generation and verification.
When verifying a proof, we compute the MMR root hash using the proof's information and the data being verified as part of the MMR.
By hashing the data to be verified, we can use the **local tree path hashes** to compute all parent node hashes, ultimately deriving the local tree peak hash.## Acknowledgments
Make sure to check the [CONTRIBUTORS](./CONTRIBUTORS.md) file for proper credit on this!