Crate merkle_cbt_lean
source ·Expand description
This crate is a no_std
compatible tool to generate Merkle trees and
and calculate root values in constrained RAM environments.
Merkle tree elements are addressable from generalized “external” memory
which could be anything from regular address space to address space
on remote storage with arbitrary access rules, or even serial input pipes.
The crate is based on CBMT implementation of the crate
merkle-cbt
.
The root calculation outcomes are matching those of the merkle-cbt
crate.
Calculation sequence differs, and lemmas have different sorting.
MerkleProof
constructions of the two crates are not interchangeable.
In this crate, all lemmas of the proof are sorted strictly left-to-right. It is also assumed that the proof was generated strictly by this algorithm: if the proof is not optimized, i.e., there are lemmas that could be merged without supplying valuer of leaves to be checked, this process will fail.
In this crate, the root calculation is done with depth graph traverse, as
opposed to width graph traverse in merkle-cbt
. This approach substantially
decreases memory requirements (other than lemmas and leaves storage space,
it stores only one hash per tree layer to total ~log(n),
opposed to storing whole layer in width traverse algorithms, ~n),
at the cost of more time needed for the calculation
(roughly O(n^2) versus O(n)).
§Key definitions
Leaf
is generalized Merkle tree node, it has a corresponding value, an
array of pre-known length N. Trait Leaf
describes how such arrays could be
read and (for proof-gen
feature) written in memory.
Hasher
describes how the values of Merkle tree nodes are calculated and
merged.
MerkleProof
contains leaves and lemmas, and root value could be
calculated for it.
§Example
use external_memory_tools::ExternalMemory;
use merkle_cbt_lean::{Hasher, Leaf, MerkleProof};
const LEN: usize = 32;
#[derive(Debug)]
struct Blake3Hasher;
impl Hasher<LEN> for Blake3Hasher {
fn make(bytes: &[u8]) -> [u8; LEN] {
blake3::hash(bytes).into()
}
fn merge(left: &[u8; LEN], right: &[u8; LEN]) -> [u8; LEN] {
blake3::hash(&[left.as_slice(), right.as_slice()].concat()).into()
}
}
#[derive(Copy, Clone, Debug)]
struct Blake3Leaf([u8; LEN]);
impl<E: ExternalMemory> Leaf<LEN, E> for Blake3Leaf {
fn read(&self, _ext_memory: &mut E) -> Result<[u8; LEN], E::ExternalMemoryError> {
Ok(self.0)
}
fn write(value: [u8; LEN], _ext_memory: &mut E) -> Result<Self, E::ExternalMemoryError> {
Ok(Self(value))
}
}
// All leaf values, deterministically sorted.
let all_values = vec![[0; LEN], [1; LEN], [2; LEN], [3; LEN], [4; LEN], [5; LEN]];
// Values that remain as leaves in the proof structure, other leaves will be
// reduced to lemmas.
// Remaining leaves will be available during the proof de-serialization.
// It is assumed that the remaining leaf values are deterministically sorted
// during serialization and de-serialization.
let remaining_as_leaves = &[[0; LEN], [3; LEN], [1; LEN]];
// Calculate `MerkleProof` for known complete set of values and known subset
// of remaining values:
let merkle_proof: MerkleProof<LEN, Blake3Leaf, (), Blake3Hasher> =
MerkleProof::for_leaves_subset(all_values, remaining_as_leaves, &mut ()).unwrap();
// Serialize `MerkleProof` for data transferring:
// Indices for remaining leaves:
let indices = merkle_proof.indices();
// Lemmas:
let lemmas = merkle_proof.lemmas;
// De-serialize `MerkleProof`:
let mut merkle_proof_restored: MerkleProof<LEN, Blake3Leaf, (), Blake3Hasher> =
MerkleProof::new_with_external_indices(
remaining_as_leaves.to_vec(),
indices,
lemmas,
).unwrap();
// Calculate root:
let root_restored = merkle_proof_restored.calculate_root(&mut ()).unwrap();
§Features
Crate supports no_std
in default-features = false
mode.
With feature proof-gen
(no-std
compatible) MerkleProof
could be
generated for a subset of leaves. proof-gen
is not needed to reconstruct
MerkleProof
from serialization, nor to calculate root for existing
MerkleProof
.
Structs§
- Node index.
- Combination of lemmas and leaves, sufficient to calculate Merkle tree root.
- Node, a combination of index and hash value.
Enums§
- Errors in Merkle tree construction and processing.
Traits§
- Describes how Merkle tree leaves are generated and merged.
- Describes how Merkle tree leaves are accessed from memory.