add sparse merkle tree impl

This commit is contained in:
Sergio Chouhy 2025-07-15 12:30:23 -03:00
parent 5c954d3d45
commit fed74bd5ef
4 changed files with 353 additions and 0 deletions

View File

@ -11,6 +11,7 @@ outer-methods = { path = "outer_methods" }
serde = "1.0"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
rand = "0.8"
sparse-merkle-tree = {path="./sparse_merkle_tree/"}
[features]
cuda = ["risc0-zkvm/cuda"]

View File

@ -0,0 +1,7 @@
[package]
name = "sparse-merkle-tree"
version = "0.1.0"
edition = "2021"
[dependencies]
sha2 = "0.10.9"

View File

@ -0,0 +1,142 @@
// Values computed as follows
//
// fn default_hashes() -> Vec<[u8; 32]> {
// let mut defaults = vec![ZERO_HASH];
// for i in 1..TREE_DEPTH {
// let h = hash_node(&defaults[i - 1], &defaults[i - 1]);
// defaults.push(h);
// }
// defaults.into_iter().rev().collect()
// }
//
//
pub(crate) const DEFAULT_HASHES: [[u8; 32]; 32] = [
[
157, 148, 193, 146, 141, 23, 128, 25, 196, 90, 21, 193, 179, 235, 209, 157, 146, 64, 171,
100, 192, 44, 121, 46, 78, 53, 190, 198, 191, 82, 85, 16,
],
[
244, 159, 70, 55, 214, 43, 252, 179, 167, 206, 218, 26, 170, 158, 22, 127, 12, 155, 130,
224, 1, 98, 105, 28, 59, 57, 233, 189, 41, 50, 63, 115,
],
[
204, 67, 6, 158, 244, 197, 238, 10, 26, 69, 178, 150, 78, 185, 192, 92, 5, 224, 36, 51,
115, 21, 130, 142, 229, 223, 102, 195, 57, 198, 17, 27,
],
[
49, 193, 198, 248, 157, 86, 23, 193, 111, 194, 178, 234, 70, 158, 128, 133, 165, 168, 43,
60, 43, 15, 129, 209, 237, 51, 21, 134, 74, 209, 147, 88,
],
[
219, 156, 83, 145, 70, 138, 195, 224, 161, 165, 121, 148, 215, 154, 104, 234, 219, 0, 91,
255, 134, 28, 229, 108, 126, 225, 184, 6, 104, 156, 105, 140,
],
[
196, 49, 181, 107, 231, 60, 253, 69, 245, 236, 7, 145, 32, 86, 58, 140, 47, 241, 0, 236,
104, 61, 176, 23, 170, 95, 128, 66, 179, 134, 192, 209,
],
[
155, 28, 109, 240, 82, 104, 71, 197, 186, 104, 178, 17, 138, 195, 57, 194, 194, 216, 96,
246, 131, 233, 26, 84, 7, 124, 175, 159, 223, 60, 187, 161,
],
[
183, 22, 254, 169, 215, 123, 104, 4, 156, 9, 23, 45, 110, 238, 115, 162, 108, 188, 142,
141, 151, 185, 20, 199, 63, 150, 94, 146, 124, 30, 53, 145,
],
[
122, 148, 43, 150, 236, 64, 36, 158, 18, 108, 140, 219, 34, 52, 143, 194, 69, 12, 185, 195,
88, 206, 30, 249, 126, 255, 18, 221, 99, 72, 18, 91,
],
[
51, 0, 157, 127, 41, 170, 190, 201, 194, 188, 222, 202, 115, 37, 229, 84, 111, 185, 104,
69, 151, 66, 69, 34, 201, 161, 159, 139, 200, 11, 135, 67,
],
[
186, 234, 98, 18, 205, 31, 46, 119, 118, 209, 66, 20, 180, 72, 129, 169, 242, 250, 48, 128,
81, 175, 108, 228, 250, 226, 170, 123, 227, 21, 242, 221,
],
[
27, 207, 232, 194, 77, 200, 137, 234, 233, 209, 180, 73, 180, 248, 193, 243, 50, 118, 191,
199, 245, 30, 142, 242, 28, 234, 249, 134, 195, 154, 138, 162,
],
[
199, 222, 136, 204, 114, 129, 19, 245, 177, 223, 179, 178, 201, 1, 202, 99, 26, 55, 146,
90, 166, 193, 206, 36, 34, 171, 170, 245, 236, 35, 142, 161,
],
[
121, 214, 101, 193, 197, 86, 227, 248, 59, 227, 3, 15, 20, 191, 124, 129, 209, 226, 93,
128, 155, 137, 229, 66, 156, 221, 29, 179, 227, 120, 78, 59,
],
[
118, 250, 222, 147, 174, 99, 105, 0, 241, 223, 160, 108, 11, 209, 143, 124, 59, 56, 11,
164, 127, 2, 3, 18, 236, 149, 4, 176, 167, 196, 138, 245,
],
[
204, 148, 248, 102, 164, 48, 65, 245, 219, 189, 191, 120, 157, 122, 63, 66, 228, 30, 143,
166, 50, 157, 68, 187, 191, 110, 195, 83, 158, 2, 133, 52,
],
[
179, 199, 88, 222, 194, 63, 148, 195, 88, 33, 190, 181, 102, 109, 100, 199, 212, 19, 198,
123, 91, 167, 50, 157, 151, 242, 194, 103, 171, 143, 88, 198,
],
[
209, 77, 39, 86, 1, 182, 123, 170, 109, 89, 182, 199, 89, 116, 244, 69, 49, 192, 149, 31,
156, 226, 106, 73, 2, 112, 161, 78, 75, 153, 68, 189,
],
[
158, 75, 216, 188, 35, 5, 86, 141, 82, 160, 215, 125, 16, 116, 45, 129, 224, 201, 105, 239,
127, 37, 135, 136, 159, 255, 91, 222, 78, 64, 60, 246,
],
[
121, 98, 24, 197, 183, 169, 52, 200, 156, 241, 142, 73, 241, 171, 113, 215, 133, 250, 13,
105, 112, 253, 80, 197, 118, 105, 228, 77, 237, 254, 195, 66,
],
[
188, 30, 229, 197, 205, 48, 162, 67, 206, 188, 130, 44, 72, 150, 168, 221, 170, 202, 59,
110, 83, 205, 9, 10, 130, 11, 129, 79, 5, 218, 164, 97,
],
[
182, 25, 214, 145, 150, 6, 219, 238, 38, 49, 166, 24, 255, 75, 56, 6, 31, 46, 163, 172,
120, 213, 141, 74, 137, 21, 191, 169, 116, 50, 172, 71,
],
[
52, 69, 229, 255, 230, 237, 127, 41, 223, 116, 249, 52, 228, 220, 231, 233, 38, 66, 188,
188, 141, 176, 216, 204, 129, 209, 214, 199, 116, 203, 218, 0,
],
[
34, 210, 93, 96, 203, 255, 15, 139, 0, 56, 109, 64, 224, 255, 168, 143, 235, 238, 144, 247,
57, 237, 244, 210, 215, 160, 98, 250, 108, 101, 127, 130,
],
[
57, 218, 36, 154, 181, 246, 243, 88, 152, 87, 31, 19, 81, 50, 15, 16, 66, 65, 78, 191, 194,
47, 162, 102, 108, 254, 215, 38, 131, 209, 233, 88,
],
[
155, 30, 22, 245, 84, 30, 111, 118, 197, 124, 53, 108, 138, 34, 183, 149, 93, 161, 54, 20,
81, 52, 135, 241, 96, 199, 21, 156, 123, 208, 105, 244,
],
[
173, 212, 84, 212, 76, 106, 120, 123, 235, 152, 249, 21, 121, 57, 137, 70, 8, 109, 9, 102,
153, 66, 109, 61, 116, 176, 20, 123, 52, 240, 173, 143,
],
[
148, 174, 121, 229, 202, 140, 51, 7, 46, 210, 185, 87, 169, 223, 189, 164, 252, 59, 133,
226, 4, 99, 142, 243, 43, 14, 151, 8, 159, 60, 235, 60,
],
[
175, 132, 242, 248, 185, 9, 188, 62, 34, 213, 240, 199, 176, 177, 75, 99, 187, 215, 70,
226, 72, 67, 45, 66, 103, 218, 50, 31, 1, 52, 216, 168,
],
[
248, 211, 204, 204, 180, 196, 230, 213, 226, 254, 251, 255, 140, 104, 170, 245, 141, 86,
82, 142, 59, 109, 142, 191, 7, 180, 33, 12, 239, 230, 161, 241,
],
[
178, 137, 222, 169, 44, 165, 171, 165, 242, 225, 137, 26, 26, 241, 27, 226, 121, 20, 196,
136, 84, 219, 15, 229, 180, 187, 149, 193, 55, 224, 242, 214,
],
[
110, 52, 11, 156, 255, 179, 122, 152, 156, 165, 68, 230, 187, 120, 10, 44, 120, 144, 29,
63, 179, 55, 56, 118, 133, 17, 163, 6, 23, 175, 160, 29,
],
];

View File

@ -0,0 +1,203 @@
use sha2::{Digest, Sha256};
use std::collections::{HashMap, HashSet};
mod default_hashes;
use default_hashes::DEFAULT_HASHES;
const TREE_DEPTH: usize = 32;
const ZERO_HASH: [u8; 32] = [
110, 52, 11, 156, 255, 179, 122, 152, 156, 165, 68, 230, 187, 120, 10, 44, 120, 144, 29, 63,
179, 55, 56, 118, 133, 17, 163, 6, 23, 175, 160, 29,
];
const ONE_HASH: [u8; 32] = [
75, 245, 18, 47, 52, 69, 84, 197, 59, 222, 46, 187, 140, 210, 183, 227, 209, 96, 10, 214, 49,
195, 133, 165, 215, 204, 226, 60, 119, 133, 69, 154,
];
/// Hash a leaf from arbitrary bytes
fn hash_leaf(data: &[u8]) -> [u8; 32] {
Sha256::digest(data).into()
}
/// Hash two child nodes
fn hash_node(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(left);
hasher.update(right);
hasher.finalize().into()
}
/// Sparse Merkle Tree with 2^32 leaves
pub struct SparseMerkleTree {
values: HashSet<u32>, // store leaf hashes
}
impl SparseMerkleTree {
pub fn new(values: HashSet<u32>) -> Self {
Self { values }
}
pub fn new_empty() -> Self {
Self {
values: HashSet::new(),
}
}
fn node_map(&self) -> HashMap<(usize, u32), [u8; 32]> {
let mut nodes: HashMap<(usize, u32), [u8; 32]> = HashMap::new();
// Start from occupied leaves
for &leaf_index in &self.values {
nodes.insert((TREE_DEPTH, leaf_index), ONE_HASH);
}
// Build tree bottom-up
for depth in (0..TREE_DEPTH).rev() {
let mut next_level = HashMap::new();
let indices: Vec<u32> = nodes
.keys()
.filter(|(d, _)| *d == depth + 1)
.map(|(_, i)| i >> 1) // parent index
.collect();
for &parent_index in indices.iter() {
let left_index = parent_index << 1;
let right_index = left_index | 1;
let left = nodes
.get(&(depth + 1, left_index))
.unwrap_or(&DEFAULT_HASHES[depth]);
let right = nodes
.get(&(depth + 1, right_index))
.unwrap_or(&DEFAULT_HASHES[depth]);
if left != &DEFAULT_HASHES[depth] || right != &DEFAULT_HASHES[depth] {
let h = hash_node(left, right);
next_level.insert((depth, parent_index), h);
}
}
nodes.extend(next_level);
}
nodes
}
pub fn root(&self) -> [u8; 32] {
let nodes = self.node_map();
nodes.get(&(0, 0)).cloned().unwrap_or(DEFAULT_HASHES[0])
}
pub fn get_authentication_path_for_index(&self, mut index: u32) -> [[u8; 32]; 32] {
let mut path = [[0u8; 32]; 32];
let nodes = self.node_map();
let mut current_index = index;
for depth in (0..32).rev() {
let sibling_index = current_index ^ 1;
let sibling_hash = nodes
.get(&(depth + 1, sibling_index))
.cloned()
.unwrap_or(DEFAULT_HASHES[depth]);
path[31 - depth] = sibling_hash;
current_index >>= 1;
}
path
}
pub fn verify_index_set(mut index: u32, path: [[u8; 32]; 32], root: [u8; 32]) -> bool {
let mut hash = ONE_HASH;
for path_value in path.iter() {
if index & 1 == 0 {
hash = hash_node(&hash, path_value);
} else {
hash = hash_node(path_value, &hash);
}
index >>= 1;
}
root == hash
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_hashes() {
assert_eq!(DEFAULT_HASHES[TREE_DEPTH - 1], ZERO_HASH);
assert_eq!(
DEFAULT_HASHES[0],
[
157, 148, 193, 146, 141, 23, 128, 25, 196, 90, 21, 193, 179, 235, 209, 157, 146,
64, 171, 100, 192, 44, 121, 46, 78, 53, 190, 198, 191, 82, 85, 16
]
);
}
#[test]
fn test_empty_tree() {
let empty_tree = SparseMerkleTree::new_empty();
assert_eq!(empty_tree.root(), DEFAULT_HASHES[0]);
}
#[test]
fn test_tree_1() {
let values: HashSet<u32> = vec![0, 1, 2, 3].into_iter().collect();
let tree = SparseMerkleTree::new(values);
assert_eq!(
tree.root(),
[
109, 94, 224, 93, 195, 77, 137, 36, 108, 105, 177, 22, 212, 17, 160, 255, 224, 61,
191, 17, 129, 10, 26, 76, 197, 42, 230, 160, 80, 44, 101, 184
]
);
}
#[test]
fn test_tree_2() {
let values: HashSet<u32> = vec![2147483648, 2147483649, 2147483650, 2147483651]
.into_iter()
.collect();
let tree = SparseMerkleTree::new(values);
assert_eq!(
tree.root(),
[
36, 178, 159, 245, 165, 76, 242, 85, 25, 218, 149, 135, 194, 127, 130, 201, 219,
187, 167, 216, 1, 222, 234, 197, 152, 156, 243, 174, 68, 27, 114, 8
]
);
}
#[test]
fn test_tree_3() {
let values: HashSet<u32> = vec![2147483648, 0, 1, 2147483649].into_iter().collect();
let tree = SparseMerkleTree::new(values);
assert_eq!(
tree.root(),
[
148, 76, 190, 191, 248, 243, 89, 40, 197, 157, 206, 23, 58, 197, 86, 169, 225, 217,
110, 166, 54, 10, 245, 175, 168, 4, 145, 220, 30, 210, 67, 113
]
);
}
#[test]
fn test_auth_path_1() {
let values: HashSet<u32> = vec![0, 1, 2, 3, 1337].into_iter().collect();
let tree = SparseMerkleTree::new(values);
let root = tree.root();
let path = tree.get_authentication_path_for_index(0);
assert!(SparseMerkleTree::verify_index_set(0, path, root));
let path = tree.get_authentication_path_for_index(1);
assert!(SparseMerkleTree::verify_index_set(1, path, root));
let path = tree.get_authentication_path_for_index(1337);
assert!(SparseMerkleTree::verify_index_set(1337, path, root));
let path = tree.get_authentication_path_for_index(1338);
assert!(!SparseMerkleTree::verify_index_set(1338, path, root));
}
}