Browse Source

Merge pull request #93 from 0xPolygonMiden/hacka-add-merkle-store

Add merkle store
al-gkr-basic-workflow
Augusto Hack 2 years ago
committed by GitHub
parent
commit
e4ddf6ffaf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 675 additions and 9 deletions
  1. +169
    -0
      src/bit.rs
  2. +12
    -0
      src/hash/rpo/digest.rs
  3. +1
    -0
      src/lib.rs
  4. +14
    -0
      src/merkle/index.rs
  5. +3
    -1
      src/merkle/merkle_tree.rs
  6. +8
    -1
      src/merkle/mod.rs
  7. +7
    -7
      src/merkle/simple_smt/mod.rs
  8. +461
    -0
      src/merkle/store.rs

+ 169
- 0
src/bit.rs

@ -0,0 +1,169 @@
/// Yields the bits of a `u64`.
pub struct BitIterator {
/// The value that is being iterated bit-wise
value: u64,
/// True bits in the `mask` are the bits that have been visited.
mask: u64,
}
impl BitIterator {
pub fn new(value: u64) -> BitIterator {
BitIterator { value, mask: 0 }
}
/// An efficient skip implementation.
///
/// Note: The compiler is smart enough to translate a `skip(n)` into a single shift instruction
/// if the code is inlined, however inlining does not always happen.
pub fn skip_front(mut self, n: u32) -> Self {
let mask = bitmask(n);
let ones = self.mask.trailing_ones();
let mask_position = ones;
self.mask ^= mask << mask_position;
self
}
/// An efficient skip from the back.
///
/// Note: The compiler is smart enough to translate a `skip(n)` into a single shift instruction
/// if the code is inlined, however inlining does not always happen.
pub fn skip_back(mut self, n: u32) -> Self {
let mask = bitmask(n);
let ones = self.mask.leading_ones();
let mask_position = u64::BITS - ones - n;
self.mask ^= mask << mask_position;
self
}
}
impl Iterator for BitIterator {
type Item = bool;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
// trailing_ones is implemented with trailing_zeros, and the zeros are computed with the
// intrinsic cttz. [Rust 1.67.0] x86 uses the `bsf` instruction. AArch64 uses the `rbit
// clz` instructions.
let ones = self.mask.trailing_ones();
if ones == u64::BITS {
None
} else {
let bit_position = ones;
let mask = 1 << bit_position;
self.mask ^= mask;
let bit = self.value & mask;
Some(bit != 0)
}
}
}
impl DoubleEndedIterator for BitIterator {
fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
// leading_ones is implemented with leading_zeros, and the zeros are computed with the
// intrinsic ctlz. [Rust 1.67.0] x86 uses the `bsr` instruction. AArch64 uses the `clz`
// instruction.
let ones = self.mask.leading_ones();
if ones == u64::BITS {
None
} else {
let bit_position = u64::BITS - ones - 1;
let mask = 1 << bit_position;
self.mask ^= mask;
let bit = self.value & mask;
Some(bit != 0)
}
}
}
#[cfg(test)]
mod test {
use super::BitIterator;
#[test]
fn test_bit_iterator() {
let v = 0b1;
let mut it = BitIterator::new(v);
assert!(it.next().unwrap(), "first bit is true");
assert!(it.all(|v| v == false), "every other value is false");
let v = 0b10;
let mut it = BitIterator::new(v);
assert!(!it.next().unwrap(), "first bit is false");
assert!(it.next().unwrap(), "first bit is true");
assert!(it.all(|v| v == false), "every other value is false");
let v = 0b10;
let mut it = BitIterator::new(v);
assert!(!it.next_back().unwrap(), "last bit is false");
assert!(!it.next().unwrap(), "first bit is false");
assert!(it.next().unwrap(), "first bit is true");
assert!(it.all(|v| v == false), "every other value is false");
}
#[test]
fn test_bit_iterator_skip() {
let v = 0b1;
let mut it = BitIterator::new(v).skip_front(1);
assert!(it.all(|v| v == false), "every other value is false");
let v = 0b10;
let mut it = BitIterator::new(v).skip_front(1);
assert!(it.next().unwrap(), "first bit is true");
assert!(it.all(|v| v == false), "every other value is false");
let high_bit = 0b1 << (u64::BITS - 1);
let mut it = BitIterator::new(high_bit).skip_back(1);
assert!(it.all(|v| v == false), "every other value is false");
let v = 0b10;
let mut it = BitIterator::new(v).skip_back(1);
assert!(!it.next_back().unwrap(), "last bit is false");
assert!(!it.next().unwrap(), "first bit is false");
assert!(it.next().unwrap(), "first bit is true");
assert!(it.all(|v| v == false), "every other value is false");
}
#[test]
fn test_skip_all() {
let v = 0b1;
let mut it = BitIterator::new(v).skip_front(u64::BITS);
assert!(it.next().is_none(), "iterator must be exhausted");
let v = 0b1;
let mut it = BitIterator::new(v).skip_back(u64::BITS);
assert!(it.next().is_none(), "iterator must be exhausted");
}
#[test]
fn test_bit_iterator_count_bits_after_skip() {
let any_value = 0b1;
for s in 0..u64::BITS {
let it = BitIterator::new(any_value).skip_front(s);
assert_eq!(it.count() as u32, u64::BITS - s)
}
let any_value = 0b1;
for s in 1..u64::BITS {
let it = BitIterator::new(any_value).skip_back(s);
assert_eq!(it.count() as u32, u64::BITS - s)
}
}
#[test]
fn test_bit_iterator_rev() {
let v = 0b1;
let mut it = BitIterator::new(v).rev();
assert!(it.nth(63).unwrap(), "the last value is true");
}
}
// UTILITIES
// ===============================================================================================
fn bitmask(s: u32) -> u64 {
match 1u64.checked_shl(s) {
Some(r) => r - 1,
None => u64::MAX,
}
}

+ 12
- 0
src/hash/rpo/digest.rs

@ -73,12 +73,24 @@ impl From<[Felt; DIGEST_SIZE]> for RpoDigest {
} }
} }
impl From<&RpoDigest> for [Felt; DIGEST_SIZE] {
fn from(value: &RpoDigest) -> Self {
value.0
}
}
impl From<RpoDigest> for [Felt; DIGEST_SIZE] { impl From<RpoDigest> for [Felt; DIGEST_SIZE] {
fn from(value: RpoDigest) -> Self { fn from(value: RpoDigest) -> Self {
value.0 value.0
} }
} }
impl From<&RpoDigest> for [u8; 32] {
fn from(value: &RpoDigest) -> Self {
value.as_bytes()
}
}
impl From<RpoDigest> for [u8; 32] { impl From<RpoDigest> for [u8; 32] {
fn from(value: RpoDigest) -> Self { fn from(value: RpoDigest) -> Self {
value.as_bytes() value.as_bytes()

+ 1
- 0
src/lib.rs

@ -4,6 +4,7 @@
#[cfg_attr(test, macro_use)] #[cfg_attr(test, macro_use)]
extern crate alloc; extern crate alloc;
mod bit;
pub mod hash; pub mod hash;
pub mod merkle; pub mod merkle;

+ 14
- 0
src/merkle/index.rs

@ -1,4 +1,5 @@
use super::{Felt, MerkleError, RpoDigest, StarkField}; use super::{Felt, MerkleError, RpoDigest, StarkField};
use crate::bit::BitIterator;
// NODE INDEX // NODE INDEX
// ================================================================================================ // ================================================================================================
@ -97,6 +98,19 @@ impl NodeIndex {
self.depth == 0 self.depth == 0
} }
/// Returns a bit iterator for the `value`.
///
/// Bits read from left-to-right represent which internal node's child should be visited to
/// arrive at the leaf. From the right-to-left the bit represent the position the hash of the
/// current element should go.
///
/// Additionally, the value that is not visisted are the sibling values necessary for a Merkle
/// opening.
pub fn bit_iterator(&self) -> BitIterator {
let depth: u32 = self.depth.into();
BitIterator::new(self.value).skip_back(u64::BITS - depth)
}
// STATE MUTATORS // STATE MUTATORS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------

+ 3
- 1
src/merkle/merkle_tree.rs

@ -9,7 +9,7 @@ use winter_math::log2;
/// A fully-balanced binary Merkle tree (i.e., a tree where the number of leaves is a power of two). /// A fully-balanced binary Merkle tree (i.e., a tree where the number of leaves is a power of two).
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct MerkleTree { pub struct MerkleTree {
nodes: Vec<Word>,
pub(crate) nodes: Vec<Word>,
} }
impl MerkleTree { impl MerkleTree {
@ -108,6 +108,8 @@ impl MerkleTree {
index.move_up(); index.move_up();
} }
debug_assert!(index.is_root(), "the path must include the root");
Ok(path.into()) Ok(path.into())
} }

+ 8
- 1
src/merkle/mod.rs

@ -1,6 +1,6 @@
use super::{ use super::{
hash::rpo::{Rpo256, RpoDigest}, hash::rpo::{Rpo256, RpoDigest},
utils::collections::{vec, BTreeMap, Vec},
utils::collections::{vec, BTreeMap, BTreeSet, Vec},
Felt, StarkField, Word, WORD_SIZE, ZERO, Felt, StarkField, Word, WORD_SIZE, ZERO,
}; };
use core::fmt; use core::fmt;
@ -29,13 +29,18 @@ pub use simple_smt::SimpleSmt;
mod mmr; mod mmr;
pub use mmr::{Mmr, MmrPeaks}; pub use mmr::{Mmr, MmrPeaks};
mod store;
pub use store::MerkleStore;
// ERRORS // ERRORS
// ================================================================================================ // ================================================================================================
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum MerkleError { pub enum MerkleError {
ConflictingRoots(Vec<Word>),
DepthTooSmall(u8), DepthTooSmall(u8),
DepthTooBig(u64), DepthTooBig(u64),
NodeNotInStorage(Word, NodeIndex),
NumLeavesNotPowerOfTwo(usize), NumLeavesNotPowerOfTwo(usize),
InvalidIndex(NodeIndex), InvalidIndex(NodeIndex),
InvalidDepth { expected: u8, provided: u8 }, InvalidDepth { expected: u8, provided: u8 },
@ -48,6 +53,7 @@ impl fmt::Display for MerkleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use MerkleError::*; use MerkleError::*;
match self { match self {
ConflictingRoots(roots) => write!(f, "the merkle paths roots do not match {roots:?}"),
DepthTooSmall(depth) => write!(f, "the provided depth {depth} is too small"), DepthTooSmall(depth) => write!(f, "the provided depth {depth} is too small"),
DepthTooBig(depth) => write!(f, "the provided depth {depth} is too big"), DepthTooBig(depth) => write!(f, "the provided depth {depth} is too big"),
NumLeavesNotPowerOfTwo(leaves) => { NumLeavesNotPowerOfTwo(leaves) => {
@ -64,6 +70,7 @@ impl fmt::Display for MerkleError {
InvalidPath(_path) => write!(f, "the provided path is not valid"), InvalidPath(_path) => write!(f, "the provided path is not valid"),
InvalidEntriesCount(max, provided) => write!(f, "the provided number of entries is {provided}, but the maximum for the given depth is {max}"), InvalidEntriesCount(max, provided) => write!(f, "the provided number of entries is {provided}, but the maximum for the given depth is {max}"),
NodeNotInSet(index) => write!(f, "the node indexed by {index} is not in the set"), NodeNotInSet(index) => write!(f, "the node indexed by {index} is not in the set"),
NodeNotInStorage(hash, index) => write!(f, "the node {:?} indexed by {} and depth {} is not in the storage", hash, index.value(), index.depth(),),
} }
} }
} }

+ 7
- 7
src/merkle/simple_smt/mod.rs

@ -15,7 +15,7 @@ mod tests;
pub struct SimpleSmt { pub struct SimpleSmt {
root: Word, root: Word,
depth: u8, depth: u8,
store: Store,
pub(crate) store: Store,
} }
impl SimpleSmt { impl SimpleSmt {
@ -207,17 +207,17 @@ impl SimpleSmt {
/// respectively. Hashes for blank subtrees at each layer are stored in `empty_hashes`, beginning /// respectively. Hashes for blank subtrees at each layer are stored in `empty_hashes`, beginning
/// with the root hash of an empty tree, and ending with the zero value of a leaf node. /// with the root hash of an empty tree, and ending with the zero value of a leaf node.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
struct Store {
branches: BTreeMap<NodeIndex, BranchNode>,
pub(crate) struct Store {
pub(crate) branches: BTreeMap<NodeIndex, BranchNode>,
leaves: BTreeMap<u64, Word>, leaves: BTreeMap<u64, Word>,
empty_hashes: Vec<RpoDigest>,
pub(crate) empty_hashes: Vec<RpoDigest>,
depth: u8, depth: u8,
} }
#[derive(Debug, Default, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
struct BranchNode {
left: RpoDigest,
right: RpoDigest,
pub(crate) struct BranchNode {
pub(crate) left: RpoDigest,
pub(crate) right: RpoDigest,
} }
impl Store { impl Store {

+ 461
- 0
src/merkle/store.rs

@ -0,0 +1,461 @@
//! An in-memory data store for Merkle-lized data
//!
//! This is a in memory data store for Merkle trees, this store allows all the nodes of a tree
//! (leaves or internal) to live as long as necessary and without duplication, this allows the
//! implementation of efficient persistent data structures
use super::{
BTreeMap, BTreeSet, EmptySubtreeRoots, MerkleError, MerklePath, MerkleTree, NodeIndex, Rpo256,
RpoDigest, SimpleSmt, Vec, Word,
};
#[derive(Debug)]
pub struct Node {
left: RpoDigest,
right: RpoDigest,
}
pub struct MerkleStore {
nodes: BTreeMap<RpoDigest, Node>,
}
impl Default for MerkleStore {
fn default() -> Self {
Self::new()
}
}
impl MerkleStore {
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------
/// Creates an empty `MerkleStore` instance.
pub fn new() -> MerkleStore {
let mut nodes = BTreeMap::new();
// pre-populate the store with the empty hashes
let subtrees = EmptySubtreeRoots::empty_hashes(64);
for (child, parent) in subtrees.iter().zip(subtrees.iter().skip(1)) {
nodes.insert(
*parent,
Node {
left: *child,
right: *child,
},
);
}
MerkleStore { nodes }
}
/// Adds all the nodes of a Merkle tree represented by `leaves`.
///
/// This will instantiate a Merkle tree using `leaves` and include all the nodes into the
/// storage.
///
/// # Errors
///
/// This method may return the following errors:
/// - `DepthTooSmall` if leaves is empty or contains only 1 element
/// - `NumLeavesNotPowerOfTwo` if the number of leaves is not a power-of-two
pub fn add_merkle_tree(&mut self, leaves: Vec<Word>) -> Result<Word, MerkleError> {
let layers = leaves.len().ilog2();
let tree = MerkleTree::new(leaves)?;
let mut depth = 0;
let mut parent_offset = 1;
let mut child_offset = 2;
while depth < layers {
let layer_size = 1usize << depth;
for _ in 0..layer_size {
// merkle tree is using level form representation, so left and right siblings are
// next to each other
let left = tree.nodes[child_offset];
let right = tree.nodes[child_offset + 1];
self.nodes.insert(
tree.nodes[parent_offset].into(),
Node {
left: left.into(),
right: right.into(),
},
);
parent_offset += 1;
child_offset += 2;
}
depth += 1;
}
Ok(tree.nodes[1])
}
/// Adds all the nodes of a Sparse Merkle tree represented by `entries`.
///
/// This will instantiate a Sparse Merkle tree using `entries` and include all the nodes into
/// the storage.
///
/// # Errors
///
/// This will return `InvalidEntriesCount` if the length of `entries` is not `63`.
pub fn add_sparse_merkle_tree<R, I>(&mut self, entries: R) -> Result<Word, MerkleError>
where
R: IntoIterator<IntoIter = I>,
I: Iterator<Item = (u64, Word)> + ExactSizeIterator,
{
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH)?.with_leaves(entries)?;
for branch in smt.store.branches.values() {
let parent = Rpo256::merge(&[branch.left, branch.right]);
self.nodes.insert(
parent,
Node {
left: branch.left,
right: branch.right,
},
);
}
Ok(smt.root())
}
/// Adds all the nodes of a Merkle path represented by `path`.
///
/// This will compute the sibling elements determined by the Merkle `path` and `node`, and
/// include all the nodes into the storage.
pub fn add_merkle_path(
&mut self,
index_value: u64,
node: Word,
path: MerklePath,
) -> Result<Word, MerkleError> {
let mut node = node;
let mut index = NodeIndex::new(self.nodes.len() as u8, index_value);
for sibling in path {
let (left, right) = match index.is_value_odd() {
true => (sibling, node),
false => (node, sibling),
};
let parent = Rpo256::merge(&[left.into(), right.into()]);
self.nodes.insert(
parent,
Node {
left: left.into(),
right: right.into(),
},
);
index.move_up();
node = parent.into();
}
Ok(node)
}
/// Adds all the nodes of multiple Merkle paths into the store.
///
/// This will compute the sibling elements for each Merkle `path` and include all the nodes
/// into the storage.
///
/// # Errors
///
/// Every path must resolve to the same root, otherwise this will return an `ConflictingRoots`
/// error.
pub fn add_merkle_paths<I>(&mut self, paths: I) -> Result<Word, MerkleError>
where
I: IntoIterator<Item = (u64, Word, MerklePath)>,
{
let paths: Vec<(u64, Word, MerklePath)> = paths.into_iter().collect();
let roots: BTreeSet<RpoDigest> = paths
.iter()
.map(|(index, node, path)| path.compute_root(*index, *node).into())
.collect();
if roots.len() != 1 {
return Err(MerkleError::ConflictingRoots(
roots.iter().map(|v| Word::from(*v)).collect(),
));
}
for (index_value, node, path) in paths {
self.add_merkle_path(index_value, node, path)?;
}
// Returns the parent of the last paths (assumes all paths have the same parent) or empty
// The length of unique_roots is checked above, so this wont panic
Ok(roots.iter().next().unwrap().into())
}
// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------
/// Returns the node at `index` rooted on the tree `root`.
///
/// # Errors
///
/// This will return `NodeNotInStorage` if the element is not present in the store.
pub fn get_node(&self, root: Word, index: NodeIndex) -> Result<Word, MerkleError> {
let mut hash: RpoDigest = root.into();
for bit in index.bit_iterator().rev() {
let node = self
.nodes
.get(&hash)
.ok_or(MerkleError::NodeNotInStorage(hash.into(), index))?;
hash = if bit { node.right } else { node.left }
}
Ok(hash.into())
}
/// Returns the path for the node at `index` rooted on the tree `root`.
///
/// # Errors
///
/// This will return `NodeNotInStorage` if the element is not present in the store.
pub fn get_path(
&self,
root: Word,
index: NodeIndex,
) -> Result<(Word, MerklePath), MerkleError> {
let mut hash: RpoDigest = root.into();
let mut path = Vec::new();
let node = RpoDigest::default();
for bit in index.bit_iterator() {
let node = self
.nodes
.get(&hash)
.ok_or(MerkleError::NodeNotInStorage(hash.into(), index))?;
hash = if bit {
path.push(node.left.into());
node.right
} else {
path.push(node.right.into());
node.left
}
}
Ok((node.into(), MerklePath::new(path)))
}
// DATA MUTATORS
// --------------------------------------------------------------------------------------------
pub fn set_node(
&mut self,
root: Word,
index: NodeIndex,
value: Word,
) -> Result<Word, MerkleError> {
let (current_node, path) = self.get_path(root, index)?;
if current_node != value {
self.add_merkle_path(index.value(), value, path)
} else {
Ok(root)
}
}
pub fn merge_roots(&mut self, root1: Word, root2: Word) -> Result<Word, MerkleError> {
let root1: RpoDigest = root1.into();
let root2: RpoDigest = root2.into();
if !self.nodes.contains_key(&root1) {
Err(MerkleError::NodeNotInStorage(
root1.into(),
NodeIndex::new(0, 0),
))
} else if !self.nodes.contains_key(&root1) {
Err(MerkleError::NodeNotInStorage(
root2.into(),
NodeIndex::new(0, 0),
))
} else {
let parent: Word = Rpo256::merge(&[root1, root2]).into();
self.nodes.insert(
parent.into(),
Node {
left: root1,
right: root2,
},
);
Ok(parent)
}
}
}
#[cfg(test)]
mod test {
use super::{MerkleError, MerkleStore, MerkleTree, NodeIndex, SimpleSmt, Word};
use crate::merkle::int_to_node;
use crate::merkle::MerklePathSet;
const KEYS4: [u64; 4] = [0, 1, 2, 3];
const LEAVES4: [Word; 4] = [
int_to_node(1),
int_to_node(2),
int_to_node(3),
int_to_node(4),
];
#[test]
fn test_add_merkle_tree() -> Result<(), MerkleError> {
let mut store = MerkleStore::default();
let mtree = MerkleTree::new(LEAVES4.to_vec())?;
store.add_merkle_tree(LEAVES4.to_vec())?;
assert!(
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 0))
.is_ok(),
"node 0 must be in the tree"
);
assert!(
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 1))
.is_ok(),
"node 1 must be in the tree"
);
assert!(
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 2))
.is_ok(),
"node 2 must be in the tree"
);
assert!(
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 3))
.is_ok(),
"node 3 must be in the tree"
);
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 0))
.expect("node 0 must be in tree");
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 1))
.expect("node 1 must be in tree");
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 2))
.expect("node 2 must be in tree");
store
.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 3))
.expect("node 3 must be in tree");
Ok(())
}
#[test]
fn test_get_node_returns_self_for_root() {
let store = MerkleStore::default();
let root_idx = NodeIndex::new(0, 0);
// the root does not need any lookups in the storage itself, so the value is just returned
assert_eq!(store.get_node(LEAVES4[0], root_idx).unwrap(), LEAVES4[0]);
assert_eq!(store.get_node(LEAVES4[1], root_idx).unwrap(), LEAVES4[1]);
assert_eq!(store.get_node(LEAVES4[2], root_idx).unwrap(), LEAVES4[2]);
assert_eq!(store.get_node(LEAVES4[3], root_idx).unwrap(), LEAVES4[3]);
}
#[test]
fn test_get_invalid_node() {
let mut store = MerkleStore::default();
let mtree = MerkleTree::new(LEAVES4.to_vec()).expect("creating a merkle tree must work");
store
.add_merkle_tree(LEAVES4.to_vec())
.expect("adding a merkle tree to the store must work");
let _ = store.get_node(mtree.root(), NodeIndex::new(mtree.depth(), 3));
}
#[test]
fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> {
let mut store = MerkleStore::default();
let keys2: [u64; 2] = [0, 1];
let leaves2: [Word; 2] = [int_to_node(1), int_to_node(2)];
store.add_sparse_merkle_tree(keys2.into_iter().zip(leaves2.into_iter()))?;
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH)
.unwrap()
.with_leaves(keys2.into_iter().zip(leaves2.into_iter()))
.unwrap();
let idx = NodeIndex::new(1, 0);
assert_eq!(
store.get_node(smt.root(), idx).unwrap(),
smt.get_node(&idx).unwrap()
);
Ok(())
}
#[test]
fn test_add_sparse_merkle_tree() -> Result<(), MerkleError> {
let mut store = MerkleStore::default();
store.add_sparse_merkle_tree(KEYS4.into_iter().zip(LEAVES4.into_iter()))?;
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH)
.unwrap()
.with_leaves(KEYS4.into_iter().zip(LEAVES4.into_iter()))
.unwrap();
let idx = NodeIndex::new(1, 0);
assert_eq!(
store.get_node(smt.root(), idx).unwrap(),
smt.get_node(&idx).unwrap()
);
let idx = NodeIndex::new(1, 1);
assert_eq!(
store.get_node(smt.root(), idx).unwrap(),
smt.get_node(&idx).unwrap()
);
Ok(())
}
#[test]
fn test_add_merkle_paths() -> Result<(), MerkleError> {
let mut store = MerkleStore::default();
let mtree = MerkleTree::new(LEAVES4.to_vec())?;
let i0 = 0;
let p0 = mtree.get_path(NodeIndex::new(2, i0)).unwrap();
let i1 = 1;
let p1 = mtree.get_path(NodeIndex::new(2, i1)).unwrap();
let i2 = 2;
let p2 = mtree.get_path(NodeIndex::new(2, i2)).unwrap();
let i3 = 3;
let p3 = mtree.get_path(NodeIndex::new(2, i3)).unwrap();
let paths = [
(i0, LEAVES4[i0 as usize], p0),
(i1, LEAVES4[i1 as usize], p1),
(i2, LEAVES4[i2 as usize], p2),
(i3, LEAVES4[i3 as usize], p3),
];
store
.add_merkle_paths(paths.clone())
.expect("the valid paths must work");
let set = MerklePathSet::new(3).with_paths(paths).unwrap();
assert_eq!(
set.get_node(NodeIndex::new(3, 0)).unwrap(),
store.get_node(set.root(), NodeIndex::new(2, 0b00)).unwrap(),
);
assert_eq!(
set.get_node(NodeIndex::new(3, 1)).unwrap(),
store.get_node(set.root(), NodeIndex::new(2, 0b01)).unwrap(),
);
assert_eq!(
set.get_node(NodeIndex::new(3, 2)).unwrap(),
store.get_node(set.root(), NodeIndex::new(2, 0b10)).unwrap(),
);
assert_eq!(
set.get_node(NodeIndex::new(3, 3)).unwrap(),
store.get_node(set.root(), NodeIndex::new(2, 0b11)).unwrap(),
);
Ok(())
}
}

Loading…
Cancel
Save