use alloc::{
collections::{BTreeMap, BTreeSet},
vec::Vec,
};
use assert_matches::assert_matches;
use itertools::Itertools;
use proptest::prelude::*;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use super::{PartialSmt, SMT_DEPTH, serialization::property_tests::arbitrary_valid_word};
use crate::{
EMPTY_WORD, Felt, ONE, Word, ZERO,
merkle::{
EmptySubtreeRoots, MerkleError,
smt::{Smt, SmtLeaf},
},
rand::test_utils::ContinuousRng,
utils::{Deserializable, Serializable},
};
fn random_word<R: Rng>(rng: &mut R) -> Word {
Word::new([
Felt::new_unchecked(rng.random::<u64>() % Felt::ORDER),
Felt::new_unchecked(rng.random::<u64>() % Felt::ORDER),
Felt::new_unchecked(rng.random::<u64>() % Felt::ORDER),
Felt::new_unchecked(rng.random::<u64>() % Felt::ORDER),
])
}
#[test]
fn partial_smt_new_with_no_entries() {
let mut rng = ChaCha20Rng::from_seed([1u8; 32]);
let key0 = random_word(&mut rng);
let value0 = random_word(&mut rng);
let full = Smt::with_entries([(key0, value0)]).unwrap();
let partial_smt = PartialSmt::new(full.root());
assert!(!partial_smt.tracks_leaves());
assert_eq!(partial_smt.num_entries(), 0);
assert_eq!(partial_smt.num_leaves(), 0);
assert_eq!(partial_smt.entries().count(), 0);
assert_eq!(partial_smt.leaves().count(), 0);
assert_eq!(partial_smt.root(), full.root());
}
#[test]
fn partial_smt_non_empty_root_no_proofs() {
let mut rng = ChaCha20Rng::from_seed([2u8; 32]);
let key = random_word(&mut rng);
let value = random_word(&mut rng);
let full = Smt::with_entries([(key, value)]).unwrap();
let mut partial = PartialSmt::new(full.root());
assert!(partial.get_value(&key).is_err());
assert!(partial.insert(key, value).is_err());
let empty_key = random_word(&mut rng);
assert!(partial.get_value(&empty_key).is_err());
assert!(partial.insert(empty_key, value).is_err());
}
#[test]
fn partial_smt_insert_and_remove() {
let mut rng = ChaCha20Rng::from_seed([3u8; 32]);
let key0 = random_word(&mut rng);
let key1 = random_word(&mut rng);
let key2 = random_word(&mut rng);
let key_empty = random_word(&mut rng);
let value0 = random_word(&mut rng);
let value1 = random_word(&mut rng);
let value2 = random_word(&mut rng);
let mut kv_pairs = vec![(key0, value0), (key1, value1), (key2, value2)];
kv_pairs.reserve(1000);
for _ in 0..1000 {
let key = random_word(&mut rng);
let value = random_word(&mut rng);
kv_pairs.push((key, value));
}
let mut full = Smt::with_entries(kv_pairs).unwrap();
let proof0 = full.open(&key0);
let proof2 = full.open(&key2);
let proof_empty = full.open(&key_empty);
assert!(proof_empty.leaf().is_empty());
let mut partial = PartialSmt::from_proofs([proof0, proof2, proof_empty]).unwrap();
assert_eq!(full.root(), partial.root());
assert_eq!(partial.get_value(&key0).unwrap(), value0);
let error = partial.get_value(&key1).unwrap_err();
assert_matches!(error, MerkleError::UntrackedKey(_));
assert_eq!(partial.get_value(&key2).unwrap(), value2);
let new_value0 = random_word(&mut rng);
let new_value2 = random_word(&mut rng);
let new_value_empty_key = random_word(&mut rng);
full.insert(key0, new_value0).unwrap();
full.insert(key2, new_value2).unwrap();
full.insert(key_empty, new_value_empty_key).unwrap();
partial.insert(key0, new_value0).unwrap();
partial.insert(key2, new_value2).unwrap();
partial.insert(key_empty, new_value_empty_key).unwrap();
assert_eq!(full.root(), partial.root());
assert_eq!(partial.get_value(&key0).unwrap(), new_value0);
assert_eq!(partial.get_value(&key2).unwrap(), new_value2);
assert_eq!(partial.get_value(&key_empty).unwrap(), new_value_empty_key);
full.insert(key0, EMPTY_WORD).unwrap();
partial.insert(key0, EMPTY_WORD).unwrap();
assert_eq!(full.root(), partial.root());
assert_eq!(partial.get_value(&key0).unwrap(), EMPTY_WORD);
assert_eq!(full.open(&key0), partial.open(&key0).unwrap());
assert_eq!(full.open(&key2), partial.open(&key2).unwrap());
let error = partial.clone().insert(key1, random_word(&mut rng)).unwrap_err();
assert_matches!(error, MerkleError::UntrackedKey(_));
let error = partial.insert(key1, EMPTY_WORD).unwrap_err();
assert_matches!(error, MerkleError::UntrackedKey(_));
}
#[test]
fn partial_smt_multiple_leaf_success() {
let mut rng = ChaCha20Rng::from_seed([4u8; 32]);
let key0 = Word::from([ZERO, ZERO, ZERO, ONE]);
let key1 = Word::from([ONE, ONE, ONE, ONE]);
let key2 = random_word(&mut rng);
let value0 = random_word(&mut rng);
let value1 = random_word(&mut rng);
let value2 = random_word(&mut rng);
let full = Smt::with_entries([(key0, value0), (key1, value1), (key2, value2)]).unwrap();
let SmtLeaf::Multiple(_) = full.get_leaf(&key0) else {
panic!("expected full tree to produce multiple leaf")
};
let proof0 = full.open(&key0);
let proof2 = full.open(&key2);
let partial = PartialSmt::from_proofs([proof0, proof2]).unwrap();
assert_eq!(partial.root(), full.root());
assert_eq!(partial.get_leaf(&key0).unwrap(), full.get_leaf(&key0));
assert_eq!(partial.get_leaf(&key1).unwrap(), full.get_leaf(&key1));
assert_eq!(partial.get_leaf(&key2).unwrap(), full.get_leaf(&key2));
}
#[test]
fn partial_smt_root_mismatch_on_empty_values() {
let mut rng = ChaCha20Rng::from_seed([5u8; 32]);
let key0 = random_word(&mut rng);
let key1 = random_word(&mut rng);
let key2 = random_word(&mut rng);
let value0 = EMPTY_WORD;
let value1 = random_word(&mut rng);
let value2 = EMPTY_WORD;
let kv_pairs = vec![(key0, value0)];
let mut full = Smt::with_entries(kv_pairs).unwrap();
let stale_proof = full.open(&key2);
full.insert(key1, value1).unwrap();
full.insert(key2, value2).unwrap();
let mut partial = PartialSmt::new(full.root());
let err = partial.add_proof(stale_proof).unwrap_err();
assert_matches!(err, MerkleError::ConflictingRoots { .. });
}
#[test]
fn partial_smt_root_mismatch_on_non_empty_values() {
let mut rng = ChaCha20Rng::from_seed([6u8; 32]);
let key0 = random_word(&mut rng);
let key1 = random_word(&mut rng);
let key2 = random_word(&mut rng);
let value0 = random_word(&mut rng);
let value1 = random_word(&mut rng);
let value2 = random_word(&mut rng);
let kv_pairs = vec![(key0, value0), (key1, value1)];
let mut full = Smt::with_entries(kv_pairs).unwrap();
let stale_proof = full.open(&key0);
full.insert(key2, value2).unwrap();
let mut partial = PartialSmt::new(full.root());
let err = partial.add_proof(stale_proof).unwrap_err();
assert_matches!(err, MerkleError::ConflictingRoots { .. });
}
#[test]
fn partial_smt_from_proofs_fails_on_root_mismatch() {
let mut rng = ChaCha20Rng::from_seed([7u8; 32]);
let key0 = random_word(&mut rng);
let key1 = random_word(&mut rng);
let value0 = random_word(&mut rng);
let value1 = random_word(&mut rng);
let mut full = Smt::with_entries([(key0, value0)]).unwrap();
let stale_proof = full.open(&key0);
full.insert(key1, value1).unwrap();
let err = PartialSmt::from_proofs([full.open(&key1), stale_proof]).unwrap_err();
assert_matches!(err, MerkleError::ConflictingRoots { .. });
}
#[test]
fn partial_smt_iterator_apis() {
let mut rng = ChaCha20Rng::from_seed([8u8; 32]);
let key0 = random_word(&mut rng);
let key1 = random_word(&mut rng);
let key2 = random_word(&mut rng);
let key_empty = random_word(&mut rng);
let value0 = random_word(&mut rng);
let value1 = random_word(&mut rng);
let value2 = random_word(&mut rng);
let mut kv_pairs = vec![(key0, value0), (key1, value1), (key2, value2)];
kv_pairs.reserve(1000);
for _ in 0..1000 {
let key = random_word(&mut rng);
let value = random_word(&mut rng);
kv_pairs.push((key, value));
}
let full = Smt::with_entries(kv_pairs).unwrap();
let proof0 = full.open(&key0);
let proof2 = full.open(&key2);
let proof_empty = full.open(&key_empty);
assert!(proof_empty.leaf().is_empty());
let proofs = [proof0, proof2, proof_empty];
let partial = PartialSmt::from_proofs(proofs.clone()).unwrap();
assert!(partial.tracks_leaves());
assert_eq!(full.root(), partial.root());
assert_eq!(partial.num_entries(), 2);
assert_eq!(partial.num_leaves(), 2);
let expected_leaves: BTreeMap<_, _> =
[SmtLeaf::new_single(key0, value0), SmtLeaf::new_single(key2, value2)]
.into_iter()
.map(|leaf| (leaf.index(), leaf))
.collect();
let actual_leaves = partial
.leaves()
.map(|(idx, leaf)| (idx, leaf.clone()))
.collect::<BTreeMap<_, _>>();
assert_eq!(actual_leaves.len(), expected_leaves.len());
assert_eq!(actual_leaves, expected_leaves);
assert_eq!(partial.num_leaves(), 2);
let partial_inner_nodes: BTreeSet<_> =
partial.inner_nodes().flat_map(|node| [node.left, node.right]).collect();
let empty_subtree_roots: BTreeSet<_> = (0..SMT_DEPTH)
.map(|depth| *EmptySubtreeRoots::entry(SMT_DEPTH, depth))
.collect();
for merkle_path in proofs.into_iter().map(|proof| proof.into_parts().0) {
for (idx, digest) in merkle_path.into_iter().enumerate() {
assert!(
partial_inner_nodes.contains(&digest) || empty_subtree_roots.contains(&digest),
"failed at idx {idx}"
);
}
}
}
#[test]
fn partial_smt_tracks_leaves() {
assert!(!PartialSmt::default().tracks_leaves());
}
#[test]
fn partial_smt_with_empty_leaves_serialization_roundtrip() {
let mut rng = ChaCha20Rng::from_seed([9u8; 32]);
let partial_smt = PartialSmt::new(random_word(&mut rng));
assert_eq!(partial_smt, PartialSmt::read_from_bytes(&partial_smt.to_bytes()).unwrap());
}
#[test]
fn partial_smt_serialization_roundtrip() {
let mut rng = ChaCha20Rng::from_seed([10u8; 32]);
let key = random_word(&mut rng);
let val = random_word(&mut rng);
let key_1 = random_word(&mut rng);
let val_1 = random_word(&mut rng);
let key_2 = random_word(&mut rng);
let val_2 = random_word(&mut rng);
let smt: Smt = Smt::with_entries([(key, val), (key_1, val_1), (key_2, val_2)]).unwrap();
let partial_smt = PartialSmt::from_proofs([smt.open(&key)]).unwrap();
assert_eq!(partial_smt.root(), smt.root());
assert_matches!(partial_smt.open(&key_1), Err(MerkleError::UntrackedKey(_)));
assert_matches!(partial_smt.open(&key), Ok(_));
let bytes = partial_smt.to_bytes();
let decoded = PartialSmt::read_from_bytes(&bytes).unwrap();
assert_eq!(partial_smt.num_entries, decoded.num_entries);
assert_eq!(partial_smt.root(), decoded.root());
assert_eq!(partial_smt, decoded);
}
#[test]
fn partial_smt_add_proof_num_entries() {
let mut rng = ChaCha20Rng::from_seed([11u8; 32]);
let key0 = Word::from([ZERO, ZERO, ZERO, ONE]);
let key1 = Word::from([ONE, ONE, ONE, ONE]);
let key2 = Word::from([ONE, ONE, ONE, Felt::new_unchecked(5)]);
let value0 = random_word(&mut rng);
let value1 = random_word(&mut rng);
let value2 = random_word(&mut rng);
let full = Smt::with_entries([(key0, value0), (key1, value1), (key2, value2)]).unwrap();
let mut partial = PartialSmt::new(full.root());
partial.add_proof(full.open(&key0)).unwrap();
assert_eq!(partial.num_entries(), 2);
partial.add_proof(full.open(&key2)).unwrap();
assert_eq!(partial.num_entries(), 3);
partial.insert(key0, Word::empty()).unwrap();
assert_eq!(partial.num_entries(), 2);
}
#[test]
fn partial_smt_tracking_visualization() {
const LEAF_0: u64 = 0;
const LEAF_1: u64 = 1 << 61;
const LEAF_2: u64 = 1 << 62;
const LEAF_3: u64 = (1 << 62) | (1 << 61);
const LEAF_4: u64 = 1 << 63;
const LEAF_5: u64 = (1 << 63) | (1 << 61);
const LEAF_6: u64 = (1 << 63) | (1 << 62);
const LEAF_7: u64 = (1 << 63) | (1 << 62) | (1 << 61);
let key_0 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_0)]);
let key_1 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_1)]);
let key_2 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_2)]);
let key_3 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_3)]);
let key_4 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_4)]);
let key_5 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_5)]);
let key_6 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_6)]);
let key_7 = Word::from([ZERO, ZERO, ZERO, Felt::new_unchecked(LEAF_7)]);
let mut rng = ChaCha20Rng::from_seed([12u8; 32]);
let mut full =
Smt::with_entries([(key_1, random_word(&mut rng)), (key_3, random_word(&mut rng))])
.unwrap();
let proof_1 = full.open(&key_1);
let mut partial = PartialSmt::from_proofs([proof_1]).unwrap();
assert_eq!(full.root(), partial.root());
let new_value_1 = random_word(&mut rng);
full.insert(key_1, new_value_1).unwrap();
partial.insert(key_1, new_value_1).unwrap();
assert_eq!(full.root(), partial.root());
let value_0 = random_word(&mut rng);
full.insert(key_0, value_0).unwrap();
partial.insert(key_0, value_0).unwrap();
assert_eq!(full.root(), partial.root());
let value_4 = random_word(&mut rng);
full.insert(key_4, value_4).unwrap();
partial.insert(key_4, value_4).unwrap();
assert_eq!(full.root(), partial.root());
let value_5 = random_word(&mut rng);
full.insert(key_5, value_5).unwrap();
partial.insert(key_5, value_5).unwrap();
assert_eq!(full.root(), partial.root());
let value_6 = random_word(&mut rng);
full.insert(key_6, value_6).unwrap();
partial.insert(key_6, value_6).unwrap();
assert_eq!(full.root(), partial.root());
let value_7 = random_word(&mut rng);
full.insert(key_7, value_7).unwrap();
partial.insert(key_7, value_7).unwrap();
assert_eq!(full.root(), partial.root());
let result = partial.insert(key_2, random_word(&mut rng));
assert_matches!(result, Err(MerkleError::UntrackedKey(_)));
let result = partial.insert(key_3, random_word(&mut rng));
assert_matches!(result, Err(MerkleError::UntrackedKey(_)));
assert_eq!(full.root(), partial.root());
}
#[test]
fn partial_smt_implicit_empty_tree() {
let mut rng = ChaCha20Rng::from_seed([13u8; 32]);
let mut full = Smt::new();
let mut partial = PartialSmt::new(full.root());
let key = random_word(&mut rng);
let value = random_word(&mut rng);
full.insert(key, value).unwrap();
partial.insert(key, value).unwrap();
assert_eq!(full.root(), partial.root());
assert_eq!(partial.get_value(&key).unwrap(), value);
}
#[test]
fn partial_smt_implicit_insert_and_remove() {
let mut rng = ChaCha20Rng::from_seed([14u8; 32]);
let mut full = Smt::new();
let mut partial = PartialSmt::new(full.root());
let key = random_word(&mut rng);
let value = random_word(&mut rng);
full.insert(key, value).unwrap();
partial.insert(key, value).unwrap();
assert_eq!(full.root(), partial.root());
full.insert(key, EMPTY_WORD).unwrap();
partial.insert(key, EMPTY_WORD).unwrap();
assert_eq!(full.root(), partial.root());
assert_eq!(partial.get_value(&key).unwrap(), EMPTY_WORD);
assert_eq!(partial.num_entries(), 0);
assert_eq!(partial.num_leaves(), 0);
}
#[test]
fn partial_smt_deserialize_invalid_inner_node() {
let mut rng = ChaCha20Rng::from_seed([15u8; 32]);
let key = random_word(&mut rng);
let value = random_word(&mut rng);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let mut partial = PartialSmt::new(smt.root());
partial.add_proof(proof).unwrap();
let mut bytes = partial.to_bytes();
let last_idx = bytes.len() - 1;
bytes[last_idx] ^= 0xff;
let result = PartialSmt::read_from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn partial_smt_deserialize_invalid_leaf() {
let mut rng = ChaCha20Rng::from_seed([16u8; 32]);
let key = random_word(&mut rng);
let value = random_word(&mut rng);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let mut partial = PartialSmt::new(smt.root());
partial.add_proof(proof).unwrap();
let bytes = partial.to_bytes();
let leaf_value_offset = 32 + 8 + 8 + 10;
let mut tampered_bytes = bytes;
tampered_bytes[leaf_value_offset] ^= 0xff;
let result = PartialSmt::read_from_bytes(&tampered_bytes);
assert!(result.is_err());
}
#[test]
fn partial_smt_deserialize_invalid_root() {
let mut rng = ChaCha20Rng::from_seed([17u8; 32]);
let key = random_word(&mut rng);
let value = random_word(&mut rng);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let mut partial = PartialSmt::new(smt.root());
partial.add_proof(proof).unwrap();
let mut bytes = partial.to_bytes();
bytes[0] ^= 0xff;
let result = PartialSmt::read_from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn partial_smt_deserialize_leaves_count_smaller() {
let mut rng = ChaCha20Rng::from_seed([18u8; 32]);
let key = random_word(&mut rng);
let value = random_word(&mut rng);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let mut partial = PartialSmt::new(smt.root());
partial.add_proof(proof).unwrap();
let mut bytes = partial.to_bytes();
let leaves_count_offset = 32;
let count =
u64::from_le_bytes(bytes[leaves_count_offset..leaves_count_offset + 8].try_into().unwrap());
let tampered_count = count.saturating_sub(1);
bytes[leaves_count_offset..leaves_count_offset + 8]
.copy_from_slice(&tampered_count.to_le_bytes());
let result = PartialSmt::read_from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn partial_smt_deserialize_leaves_count_larger() {
let mut rng = ChaCha20Rng::from_seed([19u8; 32]);
let key = random_word(&mut rng);
let value = random_word(&mut rng);
let smt = Smt::with_entries([(key, value)]).unwrap();
let proof = smt.open(&key);
let mut partial = PartialSmt::new(smt.root());
partial.add_proof(proof).unwrap();
let mut bytes = partial.to_bytes();
let leaves_count_offset = 32;
let count =
u64::from_le_bytes(bytes[leaves_count_offset..leaves_count_offset + 8].try_into().unwrap());
let tampered_count = count + 1;
bytes[leaves_count_offset..leaves_count_offset + 8]
.copy_from_slice(&tampered_count.to_le_bytes());
let result = PartialSmt::read_from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn unique_nodes_roundtrips() {
let mut rng = ContinuousRng::new([0x96; 32]);
let mut tree = PartialSmt::new(*EmptySubtreeRoots::entry(SMT_DEPTH, 0));
for _ in 0..200 {
tree.insert(rng.value(), rng.value()).unwrap();
}
let uniques = tree.to_unique_nodes();
let original_leaves = tree
.leaves()
.sorted_by_key(|(k, _)| *k)
.map(|(k, v)| (k.position(), v.clone()))
.collect::<Vec<_>>();
let unique_leaves = uniques
.leaves
.iter()
.sorted_by_key(|(k, _)| *k)
.map(|(k, v)| (*k, v.clone()))
.collect::<Vec<_>>();
assert_eq!(unique_leaves, original_leaves);
let reconstituted_tree =
PartialSmt::from_unique_nodes(uniques).expect("No data corruption has occurred in memory");
assert_eq!(reconstituted_tree, tree);
}
#[test]
fn unique_nodes_of_exclusion_proofs_roundtrips() {
let mut rng = ChaCha20Rng::from_seed([10u8; 32]);
let key = random_word(&mut rng);
let val = random_word(&mut rng);
let key_1 = random_word(&mut rng);
let val_1 = random_word(&mut rng);
let key_2 = random_word(&mut rng);
let val_2 = random_word(&mut rng);
let missing_key = random_word(&mut rng);
let smt: Smt = Smt::with_entries([(key, val), (key_1, val_1), (key_2, val_2)]).unwrap();
let partial_smt = PartialSmt::from_proofs([smt.open(&missing_key)]).unwrap();
let unique_nodes = partial_smt.to_unique_nodes();
let decoded = PartialSmt::from_unique_nodes(unique_nodes).unwrap();
assert_eq!(partial_smt, decoded);
}
#[test]
fn unique_nodes_serialization_roundtrips() {
let mut rng = ContinuousRng::new([0xab; 32]);
let mut tree = PartialSmt::new(*EmptySubtreeRoots::entry(SMT_DEPTH, 0));
for _ in 0..200 {
tree.insert(rng.value(), rng.value()).unwrap();
}
assert_eq!(PartialSmt::read_from_bytes(&tree.to_bytes()), Ok(tree));
}
proptest! {
#[test]
fn prop_unique_nodes_roundtrips(
kv_pairs in prop::collection::vec((arbitrary_valid_word(), arbitrary_valid_word()), 0..100),
) {
let mut smt = PartialSmt::new(*EmptySubtreeRoots::entry(SMT_DEPTH, 0));
for (k, v) in kv_pairs {
smt.insert(k, v)?;
}
let unique = smt.to_unique_nodes();
let result = PartialSmt::from_unique_nodes(unique)?;
prop_assert_eq!(result, smt);
}
#[test]
fn prop_serde_roundtrips(
kv_pairs in prop::collection::vec((arbitrary_valid_word(), arbitrary_valid_word()), 0..100),
) {
let mut smt = PartialSmt::new(*EmptySubtreeRoots::entry(SMT_DEPTH, 0));
for (k, v) in kv_pairs {
smt.insert(k, v)?;
}
let bytes = smt.to_bytes();
let result = PartialSmt::read_from_bytes(&bytes)?;
prop_assert_eq!(result, smt);
}
#[test]
fn prop_partial_smt_insert_roundtrip(key: Word, value: Word) {
prop_assume!(value != EMPTY_WORD);
let mut full = Smt::new();
let mut partial = PartialSmt::new(full.root());
full.insert(key, value).unwrap();
partial.insert(key, value).unwrap();
prop_assert_eq!(full.root(), partial.root());
prop_assert_eq!(partial.get_value(&key).unwrap(), value);
}
#[test]
fn prop_partial_smt_empty_serialization_roundtrip(root: Word) {
let partial_smt = PartialSmt::new(root);
let bytes = partial_smt.to_bytes();
let decoded = PartialSmt::read_from_bytes(&bytes).unwrap();
prop_assert_eq!(partial_smt, decoded);
}
}