arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/smt/full/tests.rs
src/merkle/smt/full/tests.rsRaw
  1use super::*;
  2use crate::{
  3    merkle::{EmptySubtreeRoots, MerkleStore},
  4    ONE, WORD_SIZE,
  5};
  6
  7/// This test checks that inserting twice at the same key functions as expected. The test covers
  8/// only the case where the key is alone in its leaf
  9#[test]
 10fn test_smt_insert_at_same_key() {
 11    let mut smt = Smt::default();
 12    let mut store: MerkleStore = MerkleStore::default();
 13
 14    assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0));
 15
 16    let key_1: RpoDigest = {
 17        let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
 18
 19        RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)])
 20    };
 21    let key_1_index: NodeIndex = LeafIndex::<SMT_DEPTH>::from(key_1).into();
 22
 23    let value_1 = [ONE; WORD_SIZE];
 24    let value_2 = [ONE + ONE; WORD_SIZE];
 25
 26    // Insert value 1 and ensure root is as expected
 27    {
 28        let leaf_node = build_empty_or_single_leaf_node(key_1, value_1);
 29        let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
 30
 31        let old_value_1 = smt.insert(key_1, value_1);
 32        assert_eq!(old_value_1, EMPTY_WORD);
 33
 34        assert_eq!(smt.root(), tree_root);
 35    }
 36
 37    // Insert value 2 and ensure root is as expected
 38    {
 39        let leaf_node = build_empty_or_single_leaf_node(key_1, value_2);
 40        let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
 41
 42        let old_value_2 = smt.insert(key_1, value_2);
 43        assert_eq!(old_value_2, value_1);
 44
 45        assert_eq!(smt.root(), tree_root);
 46    }
 47}
 48
 49/// This test checks that inserting twice at the same key functions as expected. The test covers
 50/// only the case where the leaf type is `SmtLeaf::Multiple`
 51#[test]
 52fn test_smt_insert_at_same_key_2() {
 53    // The most significant u64 used for both keys (to ensure they map to the same leaf)
 54    let key_msb: u64 = 42;
 55
 56    let key_already_present: RpoDigest =
 57        RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(key_msb)]);
 58    let key_already_present_index: NodeIndex =
 59        LeafIndex::<SMT_DEPTH>::from(key_already_present).into();
 60    let value_already_present = [ONE + ONE + ONE; WORD_SIZE];
 61
 62    let mut smt =
 63        Smt::with_entries(core::iter::once((key_already_present, value_already_present))).unwrap();
 64    let mut store: MerkleStore = {
 65        let mut store = MerkleStore::default();
 66
 67        let leaf_node = build_empty_or_single_leaf_node(key_already_present, value_already_present);
 68        store
 69            .set_node(*EmptySubtreeRoots::entry(SMT_DEPTH, 0), key_already_present_index, leaf_node)
 70            .unwrap();
 71        store
 72    };
 73
 74    let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(key_msb)]);
 75    let key_1_index: NodeIndex = LeafIndex::<SMT_DEPTH>::from(key_1).into();
 76
 77    assert_eq!(key_1_index, key_already_present_index);
 78
 79    let value_1 = [ONE; WORD_SIZE];
 80    let value_2 = [ONE + ONE; WORD_SIZE];
 81
 82    // Insert value 1 and ensure root is as expected
 83    {
 84        // Note: key_1 comes first because it is smaller
 85        let leaf_node = build_multiple_leaf_node(&[
 86            (key_1, value_1),
 87            (key_already_present, value_already_present),
 88        ]);
 89        let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
 90
 91        let old_value_1 = smt.insert(key_1, value_1);
 92        assert_eq!(old_value_1, EMPTY_WORD);
 93
 94        assert_eq!(smt.root(), tree_root);
 95    }
 96
 97    // Insert value 2 and ensure root is as expected
 98    {
 99        let leaf_node = build_multiple_leaf_node(&[
100            (key_1, value_2),
101            (key_already_present, value_already_present),
102        ]);
103        let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root;
104
105        let old_value_2 = smt.insert(key_1, value_2);
106        assert_eq!(old_value_2, value_1);
107
108        assert_eq!(smt.root(), tree_root);
109    }
110}
111
112/// This test ensures that the root of the tree is as expected when we add/remove 3 items at 3
113/// different keys. This also tests that the merkle paths produced are as expected.
114#[test]
115fn test_smt_insert_and_remove_multiple_values() {
116    fn insert_values_and_assert_path(
117        smt: &mut Smt,
118        store: &mut MerkleStore,
119        key_values: &[(RpoDigest, Word)],
120    ) {
121        for &(key, value) in key_values {
122            let key_index: NodeIndex = LeafIndex::<SMT_DEPTH>::from(key).into();
123
124            let leaf_node = build_empty_or_single_leaf_node(key, value);
125            let tree_root = store.set_node(smt.root(), key_index, leaf_node).unwrap().root;
126
127            let _ = smt.insert(key, value);
128
129            assert_eq!(smt.root(), tree_root);
130
131            let expected_path = store.get_path(tree_root, key_index).unwrap();
132            assert_eq!(smt.open(&key).0, expected_path.path);
133        }
134    }
135    let mut smt = Smt::default();
136    let mut store: MerkleStore = MerkleStore::default();
137
138    assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0));
139
140    let key_1: RpoDigest = {
141        let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
142
143        RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)])
144    };
145
146    let key_2: RpoDigest = {
147        let raw = 0b_11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111_u64;
148
149        RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)])
150    };
151
152    let key_3: RpoDigest = {
153        let raw = 0b_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_u64;
154
155        RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)])
156    };
157
158    let value_1 = [ONE; WORD_SIZE];
159    let value_2 = [ONE + ONE; WORD_SIZE];
160    let value_3 = [ONE + ONE + ONE; WORD_SIZE];
161
162    // Insert values in the tree
163    let key_values = [(key_1, value_1), (key_2, value_2), (key_3, value_3)];
164    insert_values_and_assert_path(&mut smt, &mut store, &key_values);
165
166    // Remove values from the tree
167    let key_empty_values = [(key_1, EMPTY_WORD), (key_2, EMPTY_WORD), (key_3, EMPTY_WORD)];
168    insert_values_and_assert_path(&mut smt, &mut store, &key_empty_values);
169
170    let empty_root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0);
171    assert_eq!(smt.root(), empty_root);
172
173    // an empty tree should have no leaves or inner nodes
174    assert!(smt.leaves.is_empty());
175    assert!(smt.inner_nodes.is_empty());
176}
177
178/// This tests that inserting the empty value does indeed remove the key-value contained at the
179/// leaf. We insert & remove 3 values at the same leaf to ensure that all cases are covered (empty,
180/// single, multiple).
181#[test]
182fn test_smt_removal() {
183    let mut smt = Smt::default();
184
185    let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
186
187    let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]);
188    let key_2: RpoDigest =
189        RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]);
190    let key_3: RpoDigest =
191        RpoDigest::from([3_u64.into(), 3_u64.into(), 3_u64.into(), Felt::new(raw)]);
192
193    let value_1 = [ONE; WORD_SIZE];
194    let value_2 = [2_u64.into(); WORD_SIZE];
195    let value_3: [Felt; 4] = [3_u64.into(); WORD_SIZE];
196
197    // insert key-value 1
198    {
199        let old_value_1 = smt.insert(key_1, value_1);
200        assert_eq!(old_value_1, EMPTY_WORD);
201
202        assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, value_1)));
203    }
204
205    // insert key-value 2
206    {
207        let old_value_2 = smt.insert(key_2, value_2);
208        assert_eq!(old_value_2, EMPTY_WORD);
209
210        assert_eq!(
211            smt.get_leaf(&key_2),
212            SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)])
213        );
214    }
215
216    // insert key-value 3
217    {
218        let old_value_3 = smt.insert(key_3, value_3);
219        assert_eq!(old_value_3, EMPTY_WORD);
220
221        assert_eq!(
222            smt.get_leaf(&key_3),
223            SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2), (key_3, value_3)])
224        );
225    }
226
227    // remove key 3
228    {
229        let old_value_3 = smt.insert(key_3, EMPTY_WORD);
230        assert_eq!(old_value_3, value_3);
231
232        assert_eq!(
233            smt.get_leaf(&key_3),
234            SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)])
235        );
236    }
237
238    // remove key 2
239    {
240        let old_value_2 = smt.insert(key_2, EMPTY_WORD);
241        assert_eq!(old_value_2, value_2);
242
243        assert_eq!(smt.get_leaf(&key_2), SmtLeaf::Single((key_1, value_1)));
244    }
245
246    // remove key 1
247    {
248        let old_value_1 = smt.insert(key_1, EMPTY_WORD);
249        assert_eq!(old_value_1, value_1);
250
251        assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Empty);
252    }
253}
254
255/// Tests that 2 key-value pairs stored in the same leaf have the same path
256#[test]
257fn test_smt_path_to_keys_in_same_leaf_are_equal() {
258    let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
259
260    let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]);
261    let key_2: RpoDigest =
262        RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]);
263
264    let value_1 = [ONE; WORD_SIZE];
265    let value_2 = [2_u64.into(); WORD_SIZE];
266
267    let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap();
268
269    assert_eq!(smt.open(&key_1), smt.open(&key_2));
270}
271
272/// Tests that an empty leaf hashes to the empty word
273#[test]
274fn test_empty_leaf_hash() {
275    let smt = Smt::default();
276
277    let leaf = smt.get_leaf(&RpoDigest::default());
278    assert_eq!(leaf.hash(), EMPTY_WORD.into());
279}
280
281/// Tests that `get_value()` works as expected
282#[test]
283fn test_smt_get_value() {
284    let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, ONE]);
285    let key_2: RpoDigest =
286        RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), 2_u64.into()]);
287
288    let value_1 = [ONE; WORD_SIZE];
289    let value_2 = [2_u64.into(); WORD_SIZE];
290
291    let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap();
292
293    let returned_value_1 = smt.get_value(&key_1);
294    let returned_value_2 = smt.get_value(&key_2);
295
296    assert_eq!(value_1, returned_value_1);
297    assert_eq!(value_2, returned_value_2);
298
299    // Check that a key with no inserted value returns the empty word
300    let key_no_value =
301        RpoDigest::from([42_u64.into(), 42_u64.into(), 42_u64.into(), 42_u64.into()]);
302
303    assert_eq!(EMPTY_WORD, smt.get_value(&key_no_value));
304}
305
306/// Tests that `entries()` works as expected
307#[test]
308fn test_smt_entries() {
309    let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, ONE]);
310    let key_2: RpoDigest =
311        RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), 2_u64.into()]);
312
313    let value_1 = [ONE; WORD_SIZE];
314    let value_2 = [2_u64.into(); WORD_SIZE];
315
316    let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap();
317
318    let mut entries = smt.entries();
319
320    // Note: for simplicity, we assume the order `(k1,v1), (k2,v2)`. If a new implementation
321    // switches the order, it is OK to modify the order here as well.
322    assert_eq!(&(key_1, value_1), entries.next().unwrap());
323    assert_eq!(&(key_2, value_2), entries.next().unwrap());
324    assert!(entries.next().is_none());
325}
326// HELPERS
327// --------------------------------------------------------------------------------------------
328
329fn build_empty_or_single_leaf_node(key: RpoDigest, value: Word) -> RpoDigest {
330    if value == EMPTY_WORD {
331        SmtLeaf::Empty.hash()
332    } else {
333        SmtLeaf::Single((key, value)).hash()
334    }
335}
336
337fn build_multiple_leaf_node(kv_pairs: &[(RpoDigest, Word)]) -> RpoDigest {
338    let elements: Vec<Felt> = kv_pairs
339        .iter()
340        .flat_map(|(key, value)| {
341            let key_elements = key.into_iter();
342            let value_elements = (*value).into_iter();
343
344            key_elements.chain(value_elements)
345        })
346        .collect();
347
348    Rpo256::hash_elements(&elements)
349}