use alloc::vec::Vec;
use assert_matches::assert_matches;
use super::{EMPTY_WORD, LeafIndex, NodeIndex, SMT_DEPTH, Smt, SmtLeaf};
use crate::{
Felt, ONE, Word,
hash::poseidon2::Poseidon2,
merkle::{
EmptySubtreeRoots,
smt::{
LEAF_DOMAIN, Map, MutationSet, NodeMutation, SmtLeafError, SmtProofError,
SparseMerkleTree, SparseMerkleTreeReader, full::MAX_LEAF_ENTRIES,
},
store::MerkleStore,
},
utils::{Deserializable, Serializable},
};
#[test]
fn test_smt_insert_at_same_key() {
let mut smt = Smt::default();
let mut store: MerkleStore = MerkleStore::default();
assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0));
let key_1: Word = {
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)])
};
let key_1_index: NodeIndex = LeafIndex::<SMT_DEPTH>::from(key_1).into();
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([ONE + ONE; Word::NUM_ELEMENTS]);
{
let leaf_node = build_empty_or_single_leaf_node(key_1, value_1);
let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
let old_value_1 = smt.insert(key_1, value_1).unwrap();
assert_eq!(old_value_1, EMPTY_WORD);
assert_eq!(smt.root(), tree_root);
}
{
let leaf_node = build_empty_or_single_leaf_node(key_1, value_2);
let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
let old_value_2 = smt.insert(key_1, value_2).unwrap();
assert_eq!(old_value_2, value_1);
assert_eq!(smt.root(), tree_root);
}
}
#[test]
fn test_smt_insert_at_same_key_2() {
let key_msb: u64 = 42;
let key_already_present = Word::from([2_u64, 2_u64, 2_u64, key_msb].map(Felt::new_unchecked));
let key_already_present_index: NodeIndex =
LeafIndex::<SMT_DEPTH>::from(key_already_present).into();
let value_already_present = Word::new([ONE + ONE + ONE; Word::NUM_ELEMENTS]);
let mut smt =
Smt::with_entries(core::iter::once((key_already_present, value_already_present))).unwrap();
let mut store: MerkleStore = {
let mut store = MerkleStore::default();
let leaf_node = build_empty_or_single_leaf_node(key_already_present, value_already_present);
store
.set_node(*EmptySubtreeRoots::entry(SMT_DEPTH, 0), key_already_present_index, leaf_node)
.unwrap();
store
};
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(key_msb)]);
let key_1_index: NodeIndex = LeafIndex::<SMT_DEPTH>::from(key_1).into();
assert_eq!(key_1_index, key_already_present_index);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([ONE + ONE; Word::NUM_ELEMENTS]);
{
let leaf_node = build_multiple_leaf_node(&[
(key_1, value_1),
(key_already_present, value_already_present),
]);
let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
let old_value_1 = smt.insert(key_1, value_1).unwrap();
assert_eq!(old_value_1, EMPTY_WORD);
assert_eq!(smt.root(), tree_root);
}
{
let leaf_node = build_multiple_leaf_node(&[
(key_1, value_2),
(key_already_present, value_already_present),
]);
let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
let old_value_2 = smt.insert(key_1, value_2).unwrap();
assert_eq!(old_value_2, value_1);
assert_eq!(smt.root(), tree_root);
}
}
#[test]
fn test_smt_insert_and_remove_multiple_values() {
fn insert_values_and_assert_path(
smt: &mut Smt,
store: &mut MerkleStore,
key_values: &[(Word, Word)],
) {
for &(key, value) in key_values {
let key_index: NodeIndex = LeafIndex::<SMT_DEPTH>::from(key).into();
let leaf_node = build_empty_or_single_leaf_node(key, value);
let tree_root = store.set_node(smt.root(), key_index, leaf_node).unwrap().root;
smt.insert(key, value).unwrap();
assert_eq!(smt.root(), tree_root);
let expected_path = store.get_path(tree_root, key_index).unwrap();
assert_eq!(smt.open(&key).into_parts().0, expected_path.path);
}
}
let mut smt = Smt::default();
let mut store: MerkleStore = MerkleStore::default();
assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0));
let key_1: Word = {
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)])
};
let key_2: Word = {
let raw = 0b_11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111_u64;
Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)])
};
let key_3: Word = {
let raw = 0b_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_u64;
Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)])
};
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([ONE + ONE; Word::NUM_ELEMENTS]);
let value_3 = Word::new([ONE + ONE + ONE; Word::NUM_ELEMENTS]);
let key_values = [(key_1, value_1), (key_2, value_2), (key_3, value_3)];
insert_values_and_assert_path(&mut smt, &mut store, &key_values);
let key_empty_values = [(key_1, EMPTY_WORD), (key_2, EMPTY_WORD), (key_3, EMPTY_WORD)];
insert_values_and_assert_path(&mut smt, &mut store, &key_empty_values);
let empty_root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0);
assert_eq!(smt.root(), empty_root);
assert!(smt.leaves.is_empty());
assert!(smt.inner_nodes.is_empty());
}
#[test]
fn test_smt_dont_store_empty_subtrees() {
use crate::merkle::smt::InnerNode;
let mut smt = Smt::default();
let node_index = NodeIndex::new(10, 42).unwrap();
let depth = node_index.depth();
let empty_subtree_node = EmptySubtreeRoots::get_inner_node(SMT_DEPTH, depth);
assert!(!smt.inner_nodes.contains_key(&node_index));
let old_node = smt.insert_inner_node(node_index, empty_subtree_node.clone());
assert_eq!(old_node, None);
assert!(!smt.inner_nodes.contains_key(&node_index));
let non_empty_node = InnerNode {
left: Word::new([ONE; 4]),
right: Word::new([ONE + ONE; 4]),
};
smt.insert_inner_node(node_index, non_empty_node.clone());
let old_node = smt.insert_inner_node(node_index, empty_subtree_node.clone());
assert_eq!(old_node, Some(non_empty_node));
assert!(!smt.inner_nodes.contains_key(&node_index));
let retrieved_node = smt.get_inner_node(node_index);
assert_eq!(retrieved_node, empty_subtree_node);
}
#[test]
fn test_smt_removal() {
let mut smt = Smt::default();
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)]);
let key_2: Word = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(raw),
]);
let key_3: Word = Word::from([
Felt::from_u32(3_u32),
Felt::from_u32(3_u32),
Felt::from_u32(3_u32),
Felt::new_unchecked(raw),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
{
let old_value_1 = smt.insert(key_1, value_1).unwrap();
assert_eq!(old_value_1, EMPTY_WORD);
assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, value_1)));
}
{
let old_value_2 = smt.insert(key_2, value_2).unwrap();
assert_eq!(old_value_2, EMPTY_WORD);
assert_eq!(
smt.get_leaf(&key_2),
SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)])
);
}
{
let old_value_3 = smt.insert(key_3, value_3).unwrap();
assert_eq!(old_value_3, EMPTY_WORD);
assert_eq!(
smt.get_leaf(&key_3),
SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2), (key_3, value_3)])
);
}
{
let old_value_3 = smt.insert(key_3, EMPTY_WORD).unwrap();
assert_eq!(old_value_3, value_3);
assert_eq!(
smt.get_leaf(&key_3),
SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)])
);
}
{
let old_value_2 = smt.insert(key_2, EMPTY_WORD).unwrap();
assert_eq!(old_value_2, value_2);
assert_eq!(smt.get_leaf(&key_2), SmtLeaf::Single((key_1, value_1)));
}
{
let old_value_1 = smt.insert(key_1, EMPTY_WORD).unwrap();
assert_eq!(old_value_1, value_1);
assert_eq!(smt.get_leaf(&key_1), SmtLeaf::new_empty(key_1.into()));
}
}
#[test]
fn test_prospective_hash() {
let mut smt = Smt::default();
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)]);
let key_2: Word = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(raw),
]);
let key_3: Word = Word::from([
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::new_unchecked(raw),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
{
let prospective = smt
.construct_prospective_leaf(smt.get_leaf(&key_1), &key_1, &value_1)
.unwrap()
.hash();
smt.insert(key_1, value_1).unwrap();
let leaf = smt.get_leaf(&key_1);
assert_eq!(
prospective,
leaf.hash(),
"prospective hash for leaf {leaf:?} did not match actual hash",
);
}
{
let prospective = smt
.construct_prospective_leaf(smt.get_leaf(&key_2), &key_2, &value_2)
.unwrap()
.hash();
smt.insert(key_2, value_2).unwrap();
let leaf = smt.get_leaf(&key_2);
assert_eq!(
prospective,
leaf.hash(),
"prospective hash for leaf {leaf:?} did not match actual hash",
);
}
{
let prospective = smt
.construct_prospective_leaf(smt.get_leaf(&key_3), &key_3, &value_3)
.unwrap()
.hash();
smt.insert(key_3, value_3).unwrap();
let leaf = smt.get_leaf(&key_3);
assert_eq!(
prospective,
leaf.hash(),
"prospective hash for leaf {leaf:?} did not match actual hash",
);
}
{
let old_leaf = smt.get_leaf(&key_3);
let old_value_3 = smt.insert(key_3, EMPTY_WORD).unwrap();
assert_eq!(old_value_3, value_3);
let prospective_leaf = smt
.construct_prospective_leaf(smt.get_leaf(&key_3), &key_3, &old_value_3)
.unwrap();
assert_eq!(
old_leaf.hash(),
prospective_leaf.hash(),
"removing and prospectively re-adding a leaf didn't yield the original leaf:\
\n original leaf: {old_leaf:?}\
\n prospective leaf: {prospective_leaf:?}",
);
}
{
let old_leaf = smt.get_leaf(&key_2);
let old_value_2 = smt.insert(key_2, EMPTY_WORD).unwrap();
assert_eq!(old_value_2, value_2);
let prospective_leaf = smt
.construct_prospective_leaf(smt.get_leaf(&key_2), &key_2, &old_value_2)
.unwrap();
assert_eq!(
old_leaf.hash(),
prospective_leaf.hash(),
"removing and prospectively re-adding a leaf didn't yield the original leaf:\
\n original leaf: {old_leaf:?}\
\n prospective leaf: {prospective_leaf:?}",
);
}
{
let old_leaf = smt.get_leaf(&key_1);
let old_value_1 = smt.insert(key_1, EMPTY_WORD).unwrap();
assert_eq!(old_value_1, value_1);
let prospective_leaf = smt
.construct_prospective_leaf(smt.get_leaf(&key_1), &key_1, &old_value_1)
.unwrap();
assert_eq!(
old_leaf.hash(),
prospective_leaf.hash(),
"removing and prospectively re-adding a leaf didn't yield the original leaf:\
\n original leaf: {old_leaf:?}\
\n prospective leaf: {prospective_leaf:?}",
);
}
}
#[test]
fn test_prospective_insertion() {
let mut smt = Smt::default();
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)]);
let key_2: Word = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(raw),
]);
let key_3: Word = Word::from([
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::new_unchecked(raw),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
let root_empty = smt.root();
let root_1 = {
smt.insert(key_1, value_1).unwrap();
smt.root()
};
let root_2 = {
smt.insert(key_2, value_2).unwrap();
smt.root()
};
let root_3 = {
smt.insert(key_3, value_3).unwrap();
smt.root()
};
let mut smt = Smt::default();
let mutations = smt.compute_mutations(vec![(key_1, value_1)]).unwrap();
assert_eq!(mutations.root(), root_1, "prospective root 1 did not match actual root 1");
let revert = apply_mutations(&mut smt, mutations);
assert_eq!(smt.root(), root_1, "mutations before and after apply did not match");
assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match");
assert_eq!(revert.root(), root_empty, "reverse mutations new root did not match");
assert_eq!(
revert.new_pairs,
Map::from_iter([(key_1, EMPTY_WORD)]),
"reverse mutations pairs did not match"
);
assert_eq!(
revert.node_mutations,
smt.inner_nodes.keys().map(|key| (*key, NodeMutation::Removal)).collect(),
"reverse mutations inner nodes did not match"
);
let mutations = smt.compute_mutations(vec![(key_2, value_2)]).unwrap();
assert_eq!(mutations.root(), root_2, "prospective root 2 did not match actual root 2");
let mutations = smt.compute_mutations(vec![(key_2, value_2), (key_3, value_3)]).unwrap();
assert_eq!(mutations.root(), root_3, "mutations before and after apply did not match");
let old_root = smt.root();
let revert = apply_mutations(&mut smt, mutations);
assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match");
assert_eq!(revert.root(), old_root, "reverse mutations new root did not match");
assert_eq!(
revert.new_pairs,
Map::from_iter([(key_2, EMPTY_WORD), (key_3, EMPTY_WORD)]),
"reverse mutations pairs did not match"
);
let pairs = vec![(key_3, EMPTY_WORD), (key_2, EMPTY_WORD), (key_1, EMPTY_WORD)];
let mutations = smt.compute_mutations(pairs).unwrap();
assert_eq!(
mutations.root(),
root_empty,
"prospective root for batch removal did not match actual root",
);
let old_root = smt.root();
let revert = apply_mutations(&mut smt, mutations);
assert_eq!(smt.root(), root_empty, "mutations before and after apply did not match");
assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match");
assert_eq!(revert.root(), old_root, "reverse mutations new root did not match");
assert_eq!(
revert.new_pairs,
Map::from_iter([(key_1, value_1), (key_2, value_2), (key_3, value_3)]),
"reverse mutations pairs did not match"
);
let pairs = vec![(key_3, value_3), (key_1, value_1), (key_2, value_2)];
let mutations = smt.compute_mutations(pairs).unwrap();
assert_eq!(mutations.root(), root_3);
smt.apply_mutations(mutations).unwrap();
assert_eq!(smt.root(), root_3);
}
#[test]
fn test_mutations_no_mutations() {
let key = Word::from([ONE, ONE, ONE, ONE]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let entries = [(key, value)];
let tree = Smt::with_entries(entries).unwrap();
let mutations = tree.compute_mutations(entries).unwrap();
assert_eq!(mutations.root(), mutations.old_root(), "Root should not change");
assert!(mutations.node_mutations().is_empty(), "Node mutations should be empty");
assert!(mutations.new_pairs().is_empty(), "There should be no new pairs");
}
#[test]
fn test_mutations_revert() {
let mut smt = Smt::default();
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(1)]);
let key_2: Word = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
]);
let key_3: Word = Word::from([
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::new_unchecked(3),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
smt.insert(key_1, value_1).unwrap();
smt.insert(key_2, value_2).unwrap();
let mutations = smt
.compute_mutations(vec![(key_1, EMPTY_WORD), (key_2, value_1), (key_3, value_3)])
.unwrap();
let original = smt.clone();
let revert = smt.apply_mutations_with_reversion(mutations).unwrap();
assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match");
assert_eq!(revert.root(), original.root(), "reverse mutations new root did not match");
smt.apply_mutations(revert).unwrap();
assert_eq!(smt, original, "SMT with applied revert mutations did not match original SMT");
}
#[test]
fn test_mutation_set_serialization() {
let mut smt = Smt::default();
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(1)]);
let key_2: Word = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
]);
let key_3: Word = Word::from([
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::from_u32(0_u32),
Felt::new_unchecked(3),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
smt.insert(key_1, value_1).unwrap();
smt.insert(key_2, value_2).unwrap();
let mutations = smt
.compute_mutations(vec![(key_1, EMPTY_WORD), (key_2, value_1), (key_3, value_3)])
.unwrap();
let serialized = mutations.to_bytes();
let deserialized = MutationSet::<SMT_DEPTH, Word, Word>::read_from_bytes(&serialized).unwrap();
assert_eq!(deserialized, mutations, "deserialized mutations did not match original");
let revert = smt.apply_mutations_with_reversion(mutations).unwrap();
let serialized = revert.to_bytes();
let deserialized = MutationSet::<SMT_DEPTH, Word, Word>::read_from_bytes(&serialized).unwrap();
assert_eq!(deserialized, revert, "deserialized mutations did not match original");
}
#[test]
fn test_smt_path_to_keys_in_same_leaf_are_equal() {
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_1: Word = Word::from([ONE, ONE, ONE, Felt::new_unchecked(raw)]);
let key_2: Word = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(raw),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap();
assert_eq!(smt.open(&key_1), smt.open(&key_2));
}
#[test]
fn test_empty_leaf_hash() {
let smt = Smt::default();
let leaf = smt.get_leaf(&Word::default());
assert_eq!(leaf.hash(), EMPTY_WORD);
}
#[test]
fn test_smt_get_value() {
let key_1: Word = Word::from([ONE, ONE, ONE, ONE]);
let key_2: Word = Word::from([2_u32, 2_u32, 2_u32, 2_u32]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap();
let returned_value_1 = smt.get_value(&key_1);
let returned_value_2 = smt.get_value(&key_2);
assert_eq!(value_1, returned_value_1);
assert_eq!(value_2, returned_value_2);
let key_no_value = Word::from([42_u32, 42_u32, 42_u32, 42_u32]);
assert_eq!(EMPTY_WORD, smt.get_value(&key_no_value));
}
#[test]
fn test_smt_entries() {
let key_1 = Word::from([ONE, ONE, ONE, ONE]);
let key_2 = Word::from([2_u32, 2_u32, 2_u32, 2_u32]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let entries = [(key_1, value_1), (key_2, value_2)];
let smt = Smt::with_entries(entries).unwrap();
let mut expected = Vec::from_iter(entries);
expected.sort_by_key(|(k, _)| *k);
let mut actual: Vec<_> = smt.entries().cloned().collect();
actual.sort_by_key(|(k, _)| *k);
assert_eq!(actual, expected);
}
#[test]
fn test_smt_check_empty_root_constant() {
let empty_root_64_depth = EmptySubtreeRoots::empty_hashes(64)[0];
assert_eq!(empty_root_64_depth, Smt::EMPTY_ROOT);
}
#[test]
fn test_empty_smt_deserialization_with_budget() {
let smt = Smt::default();
let bytes = smt.to_bytes();
let parsed = Smt::read_from_bytes_with_budget(&bytes, bytes.len()).unwrap();
assert_eq!(smt, parsed);
}
#[test]
fn test_empty_smt_leaf_serialization() {
let empty_leaf = SmtLeaf::new_empty(LeafIndex::new_max_depth(42));
let mut serialized = empty_leaf.to_bytes();
serialized.extend([1, 2, 3, 4, 5]);
let deserialized = SmtLeaf::read_from_bytes(&serialized).unwrap();
assert_eq!(empty_leaf, deserialized);
}
#[test]
fn test_empty_smt_leaf_deserialization_with_budget() {
let empty_leaf = SmtLeaf::new_empty(LeafIndex::new_max_depth(42));
let bytes = empty_leaf.to_bytes();
let deserialized = SmtLeaf::read_from_bytes_with_budget(&bytes, bytes.len()).unwrap();
assert_eq!(empty_leaf, deserialized);
}
#[test]
fn test_single_smt_leaf_serialization() {
let single_leaf = SmtLeaf::new_single(
Word::from([10_u32, 11_u32, 12_u32, 13_u32]),
Word::new([
Felt::from_u32(1_u32),
Felt::from_u32(2_u32),
Felt::from_u32(3_u32),
Felt::from_u32(4_u32),
]),
);
let mut serialized = single_leaf.to_bytes();
serialized.extend([1, 2, 3, 4, 5]);
let deserialized = SmtLeaf::read_from_bytes(&serialized).unwrap();
assert_eq!(single_leaf, deserialized);
}
#[test]
fn test_multiple_smt_leaf_serialization_success() {
let multiple_leaf = SmtLeaf::new_multiple(vec![
(
Word::from([10_u32, 11_u32, 12_u32, 13_u32]),
Word::new([
Felt::from_u32(1_u32),
Felt::from_u32(2_u32),
Felt::from_u32(3_u32),
Felt::from_u32(4_u32),
]),
),
(
Word::from([100_u32, 101_u32, 102_u32, 13_u32]),
Word::new([
Felt::from_u32(11_u32),
Felt::from_u32(12_u32),
Felt::from_u32(13_u32),
Felt::from_u32(14_u32),
]),
),
])
.unwrap();
let mut serialized = multiple_leaf.to_bytes();
serialized.extend([1, 2, 3, 4, 5]);
let deserialized = SmtLeaf::read_from_bytes(&serialized).unwrap();
assert_eq!(multiple_leaf, deserialized);
}
#[test]
fn test_max_leaf_entries_validation() {
let mut entries = Vec::new();
for i in 0..MAX_LEAF_ENTRIES {
let key = Word::new([ONE, ONE, Felt::new_unchecked(i as u64), ONE]);
let value = Word::new([ONE, ONE, ONE, Felt::new_unchecked(i as u64)]);
entries.push((key, value));
}
let result = SmtLeaf::new_multiple(entries.clone());
assert!(result.is_ok(), "Should allow exactly MAX_LEAF_ENTRIES entries");
let key = Word::new([ONE, ONE, Felt::new_unchecked(MAX_LEAF_ENTRIES as u64), ONE]);
let value = Word::new([ONE, ONE, ONE, Felt::new_unchecked(MAX_LEAF_ENTRIES as u64)]);
entries.push((key, value));
let error = SmtLeaf::new_multiple(entries).unwrap_err();
assert_matches!(
error,
SmtLeafError::TooManyLeafEntries { .. },
"should reject more than MAX_LEAF_ENTRIES entries"
);
}
#[test]
fn test_smt_proof_error_invalid_key_for_proof() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let root = smt.root();
let different_index_key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(999)]);
assert_matches!(
proof.verify_presence(&different_index_key, &value, &root),
Err(SmtProofError::InvalidKeyForProof)
);
}
#[test]
fn test_smt_proof_error_value_mismatch() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let root = smt.root();
let wrong_value = Word::new([Felt::new_unchecked(999); Word::NUM_ELEMENTS]);
assert_matches!(
proof.verify_presence(&key, &wrong_value, &root),
Err(SmtProofError::ValueMismatch { expected, actual })
if expected == wrong_value && actual == value
);
}
#[test]
fn test_smt_proof_error_conflicting_roots() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let actual_root = smt.root();
let wrong_root = Word::new([Felt::new_unchecked(999); Word::NUM_ELEMENTS]);
assert_matches!(
proof.verify_presence(&key, &value, &wrong_root),
Err(SmtProofError::ConflictingRoots { expected_root, actual_root: got_root })
if expected_root == wrong_root && got_root == actual_root
);
}
#[test]
fn test_smt_proof_verify_unset_success() {
let smt = Smt::default();
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let proof = smt.open(&key);
let root = smt.root();
proof.verify_unset(&key, &root).unwrap();
}
#[test]
fn test_smt_proof_verify_unset_fails_when_value_exists() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let root = smt.root();
assert_matches!(proof.verify_unset(&key, &root), Err(SmtProofError::ValueMismatch { .. }));
}
#[test]
fn test_smt_proof_verify_absence_success_different_value() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let actual_value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, actual_value)]).unwrap();
let proof = smt.open(&key);
let root = smt.root();
let absent_value = Word::new([Felt::new_unchecked(999); Word::NUM_ELEMENTS]);
proof.verify_absence(&key, &absent_value, &root).unwrap();
}
#[test]
fn test_smt_proof_verify_absence_success_key_unset() {
let smt = Smt::default();
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let proof = smt.open(&key);
let root = smt.root();
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
proof.verify_absence(&key, &value, &root).unwrap();
}
#[test]
fn test_smt_proof_error_value_present() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let root = smt.root();
assert_matches!(
proof.verify_absence(&key, &value, &root),
Err(SmtProofError::ValuePresent { key: k, value: v }) if k == key && v == value
);
}
#[test]
fn test_smt_proof_verify_absence_invalid_key() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let root = smt.root();
let different_index_key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(999)]);
assert_matches!(
proof.verify_absence(&different_index_key, &value, &root),
Err(SmtProofError::InvalidKeyForProof)
);
}
#[test]
fn test_smt_proof_get_returns_none_for_different_leaf() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let different_leaf_key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(999)]);
assert!(
proof.get(&different_leaf_key).is_none(),
"get() should return None for key mapping to different leaf"
);
}
#[test]
fn test_smt_proof_get_returns_empty_for_absent_key_same_leaf() {
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let absent_key_same_leaf = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(42),
]);
let result = proof.get(&absent_key_same_leaf);
assert_eq!(
result,
Some(EMPTY_WORD),
"get() should return Some(EMPTY_WORD) for absent key mapping to same leaf"
);
}
#[test]
fn test_smt_leaf_try_from_elements_empty() {
let leaf_index = LeafIndex::new_max_depth(42);
let expected = SmtLeaf::new_empty(leaf_index);
let elements: Vec<Felt> = expected.to_elements().collect();
let actual = SmtLeaf::try_from_elements(&elements, leaf_index).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_smt_leaf_try_from_elements_single_entry() {
let expected = SmtLeaf::new_single(
Word::from([10_u32, 11_u32, 12_u32, 13_u32]),
Word::from([1_u32, 2_u32, 3_u32, 4_u32]),
);
let elements: Vec<Felt> = expected.to_elements().collect();
let actual = SmtLeaf::try_from_elements(&elements, expected.index()).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_smt_leaf_try_from_elements_multiple_entries() {
let expected = SmtLeaf::new_multiple(vec![
(
Word::from([10_u32, 11_u32, 12_u32, 13_u32]),
Word::from([1_u32, 2_u32, 3_u32, 4_u32]),
),
(
Word::from([100_u32, 101_u32, 102_u32, 13_u32]),
Word::from([11_u32, 12_u32, 13_u32, 14_u32]),
),
])
.unwrap();
let elements: Vec<Felt> = expected.to_elements().collect();
let actual = SmtLeaf::try_from_elements(&elements, expected.index()).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_smt_leaf_try_from_elements_invalid_length() {
let elements = vec![Felt::from_u32(1), Felt::from_u32(2), Felt::from_u32(3)];
let leaf_index = LeafIndex::new_max_depth(42);
let result = SmtLeaf::try_from_elements(&elements, leaf_index);
assert_matches!(result, Err(SmtLeafError::DecodingError(_)));
}
#[test]
fn test_compute_mutations_rejects_duplicate_keys() {
use crate::merkle::MerkleError;
let smt = Smt::default();
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value = Word::new([ONE; Word::NUM_ELEMENTS]);
let result = smt.compute_mutations(vec![(key, value), (key, value)]);
let expected_pos = Smt::key_to_leaf_index(&key).position();
assert_matches!(result, Err(MerkleError::DuplicateValuesForIndex(pos)) if pos == expected_pos);
}
#[test]
fn test_compute_mutations_rejects_duplicate_keys_different_values() {
use crate::merkle::MerkleError;
let smt = Smt::default();
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let result = smt.compute_mutations(vec![(key, value_1), (key, value_2)]);
let expected_pos = Smt::key_to_leaf_index(&key).position();
assert_matches!(result, Err(MerkleError::DuplicateValuesForIndex(pos)) if pos == expected_pos);
}
#[test]
fn test_compute_mutations_rejects_interleaved_duplicate_keys() {
use crate::merkle::MerkleError;
let smt = Smt::default();
let key_1 = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let key_2 = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(42),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
let result = smt.compute_mutations(vec![(key_1, value_1), (key_2, value_2), (key_1, value_3)]);
let expected_pos = Smt::key_to_leaf_index(&key_1).position();
assert_matches!(result, Err(MerkleError::DuplicateValuesForIndex(pos)) if pos == expected_pos);
}
#[test]
fn test_compute_mutations_no_false_positives() {
let smt = Smt::default();
let key_1 = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let key_2 = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(42),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let result = smt.compute_mutations(vec![(key_1, value_1), (key_2, value_2)]);
assert!(result.is_ok(), "Different keys at the same leaf index should not be rejected");
}
#[test]
fn test_with_entries_rejects_duplicate_keys() {
use crate::merkle::MerkleError;
let key = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let result = Smt::with_entries(vec![(key, value_1), (key, value_2)]);
let expected_pos = Smt::key_to_leaf_index(&key).position();
assert_matches!(result, Err(MerkleError::DuplicateValuesForIndex(pos)) if pos == expected_pos);
}
#[test]
fn test_with_entries_rejects_interleaved_duplicate_keys() {
use crate::merkle::MerkleError;
let key_1 = Word::from([ONE, ONE, ONE, Felt::new_unchecked(42)]);
let key_2 = Word::from([
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(2),
Felt::new_unchecked(42),
]);
let value_1 = Word::new([ONE; Word::NUM_ELEMENTS]);
let value_2 = Word::new([Felt::from_u32(2_u32); Word::NUM_ELEMENTS]);
let value_3 = Word::new([Felt::from_u32(3_u32); Word::NUM_ELEMENTS]);
let result = Smt::with_entries(vec![(key_1, value_1), (key_2, value_2), (key_1, value_3)]);
let expected_pos = Smt::key_to_leaf_index(&key_1).position();
assert_matches!(result, Err(MerkleError::DuplicateValuesForIndex(pos)) if pos == expected_pos);
}
fn build_empty_or_single_leaf_node(key: Word, value: Word) -> Word {
if value == EMPTY_WORD {
SmtLeaf::new_empty(key.into()).hash()
} else {
SmtLeaf::Single((key, value)).hash()
}
}
fn build_multiple_leaf_node(kv_pairs: &[(Word, Word)]) -> Word {
let elements: Vec<Felt> = kv_pairs
.iter()
.flat_map(|(key, value)| {
let key_elements = key.into_iter();
let value_elements = (*value).into_iter();
key_elements.chain(value_elements)
})
.collect();
Poseidon2::hash_elements_in_domain(&elements, LEAF_DOMAIN)
}
fn apply_mutations(
smt: &mut Smt,
mutation_set: MutationSet<SMT_DEPTH, Word, Word>,
) -> MutationSet<SMT_DEPTH, Word, Word> {
let mut smt2 = smt.clone();
let reversion = smt.apply_mutations_with_reversion(mutation_set.clone()).unwrap();
smt2.apply_mutations(mutation_set).unwrap();
assert_eq!(&smt2, smt);
reversion
}