commonware_storage/mmr/
mod.rs

1//! A Merkle Mountain Range (MMR) is an append-only data structure that allows for efficient
2//! verification of the inclusion of an element, or some range of consecutive elements, in a list.
3//!
4//! # Terminology
5//!
6//! An MMR is a list of perfect binary trees (aka "mountains") of strictly decreasing height. The
7//! roots of these trees are called the "peaks" of the MMR. Each "element" stored in the MMR is
8//! represented by some leaf node in one of these perfect trees, storing a positioned hash of the
9//! element. Non-leaf nodes store a positioned hash of their children.
10//!
11//! The "size" of an MMR is the total number of nodes summed over all trees.
12//!
13//! The nodes of the MMR are ordered by a post-order traversal of the MMR trees, starting from the
14//! from tallest tree to shortest. The "position" of a node in the MMR is defined as the 0-based
15//! index of the node in this ordering. This implies the positions of elements, which are always
16//! leaves, may not be contiguous even if they were consecutively added. An element's "number" is
17//! its 0-based index in the order of element insertion. In the example below, the right-most
18//! element has position 18 and number 10.
19//!
20//! As the MMR is an append-only data structure, node positions never change and can be used as
21//! stable identifiers.
22//!
23//! The "height" of a node is 0 for a leaf, 1 for the parent of 2 leaves, and so on.
24//!
25//! The "root digest" (or just "root") of an MMR is the result of hashing together the size of the
26//! MMR and the digests of every peak in decreasing order of height.
27//!
28//! # Examples
29//!
30//! (Borrowed from <https://docs.grin.mw/wiki/chain-state/merkle-mountain-range/>): After adding 11
31//! elements to an MMR, it will have 19 nodes total with 3 peaks corresponding to 3 perfect binary
32//! trees as pictured below, with nodes identified by their positions:
33//!
34//! ```text
35//!    Height
36//!      3              14
37//!                   /    \
38//!                  /      \
39//!                 /        \
40//!                /          \
41//!      2        6            13
42//!             /   \        /    \
43//!      1     2     5      9     12     17
44//!           / \   / \    / \   /  \   /  \
45//!      0   0   1 3   4  7   8 10  11 15  16 18
46//!
47//! Number   0   1 2   3  4   5  6   7  8   9 10
48//! ```
49//!
50//! The root hash in this example is computed as:
51//!
52//! ```text
53//!
54//! Hash(19,
55//!   Hash(14,                                                  // first peak
56//!     Hash(6,
57//!       Hash(2, Hash(0, element_0), Hash(1, element_1)),
58//!       Hash(5, Hash(3, element_2), Hash(4, element_4))
59//!     )
60//!     Hash(13,
61//!       Hash(9, Hash(7, element_7), Hash(8, element_8)),
62//!       Hash(12, Hash(10, element_10), Hash(11, element_11))
63//!     )
64//!   )
65//!   Hash(17, Hash(15, element_15), Hash(16, element_16))      // second peak
66//!   Hash(18, element_18)                                      // third peak
67//! )
68//! ```
69
70use crate::mmr::hasher::Hasher;
71use commonware_cryptography::Hasher as CHasher;
72use std::future::Future;
73use thiserror::Error;
74
75pub mod bitmap;
76pub mod hasher;
77pub mod iterator;
78pub mod journaled;
79pub mod mem;
80pub mod storage;
81#[cfg(test)]
82mod tests;
83pub mod verification;
84
85/// A trait for building an MMR and computing the root.
86pub trait Builder<H: CHasher>: Send + Sync {
87    /// Add `element` to the MMR and return its position within it. The element can be an arbitrary
88    /// byte slice, and need not be converted to a digest first.
89    fn add(
90        &mut self,
91        hasher: &mut impl Hasher<H>,
92        element: &[u8],
93    ) -> impl Future<Output = Result<u64, Error>>;
94
95    /// Return the root hash of the MMR.
96    fn root(&self, hasher: &mut impl Hasher<H>) -> H::Digest;
97}
98
99/// Errors that can occur when interacting with an MMR.
100#[derive(Error, Debug)]
101pub enum Error {
102    #[error("an element required for this operation has been pruned: {0}")]
103    ElementPruned(u64),
104    #[error("metadata error: {0}")]
105    MetadataError(#[from] crate::metadata::Error),
106    #[error("journal error: {0}")]
107    JournalError(#[from] crate::journal::Error),
108    #[error("missing node: {0}")]
109    MissingNode(u64),
110    #[error("MMR is empty")]
111    Empty,
112    #[error("invalid update")]
113    InvalidUpdate,
114    #[error("invalid proof length")]
115    InvalidProofLength,
116    #[error("proof missing digest at position: {0}")]
117    MissingDigest(u64),
118    #[error("invalid size: {0}")]
119    InvalidSize(u64),
120    #[error("root mismatch")]
121    RootMismatch,
122    #[error("invalid proof")]
123    InvalidProof,
124    #[error("runtime error: {0}")]
125    Runtime(#[from] commonware_runtime::Error),
126}