Skip to main content

tasm_lib/mmr/authentication_struct/
shared.rs

1use std::collections::HashMap;
2use std::collections::HashSet;
3
4use itertools::Itertools;
5use num_traits::One;
6
7use crate::data_type::DataType;
8use crate::twenty_first::bfe;
9use crate::twenty_first::prelude::*;
10use crate::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator;
11use crate::twenty_first::util_types::mmr::shared_advanced::get_peak_heights;
12use crate::twenty_first::util_types::mmr::shared_basic::leaf_index_to_mt_index_and_peak_index;
13
14const ROOT_MT_INDEX: u64 = 1;
15
16pub(super) fn indexed_leaf_element_type() -> DataType {
17    DataType::Tuple(vec![DataType::U64, DataType::Digest])
18}
19
20/// A witness to facilitate the proving of the authenticity of a Merkle
21/// authentication struct.
22#[derive(Debug, Clone)]
23pub struct AuthStructIntegrityProof {
24    // All indices are Merkle tree node indices
25    pub nd_auth_struct_indices: Vec<u64>,
26    pub nd_sibling_indices: Vec<(u64, u64)>,
27    pub nd_siblings: Vec<(Digest, Digest)>,
28}
29
30/// An authentication structure that can be used to prove membership of a list
31/// of leaves in a Merkle tree, along with the indexed leaves in question, and
32/// the witness necessary to prove membership in a ZK program.
33#[derive(Debug, Clone)]
34pub struct AuthenticatedMerkleAuthStruct {
35    pub auth_struct: Vec<Digest>,
36    pub indexed_leafs: Vec<(u64, Digest)>,
37    pub witness: AuthStructIntegrityProof,
38}
39
40impl AuthStructIntegrityProof {
41    /// Return the Merkle tree node indices of the digests required to prove
42    /// membership for the specified leaf indices, as well as the node indices
43    /// that can be derived from the leaf indices and their authentication
44    /// path.
45    fn auth_struct_and_nd_indices(
46        num_leafs: u64,
47        leaf_indices: &[u64],
48    ) -> (Vec<u64>, Vec<(u64, u64)>) {
49        // The set of indices of nodes that need to be included in the authentications
50        // structure. In principle, every node of every authentication path is needed.
51        // The root is never needed. Hence, it is not considered below.
52        let mut node_is_needed = HashSet::new();
53
54        // The set of indices of nodes that can be computed from other nodes in the
55        // authentication structure or the leafs that are explicitly supplied during
56        // verification. Every node on the direct path from the leaf to the root can
57        // be computed by the very nature of “authentication path”.
58        let mut node_can_be_computed = HashSet::new();
59
60        for &leaf_index in leaf_indices {
61            assert!(
62                num_leafs > leaf_index,
63                "Leaf index must be less than number of leafs. Got leaf_index = {leaf_index}; num_leafs = {num_leafs}"
64            );
65
66            let mut node_index = leaf_index + num_leafs;
67            while node_index > ROOT_MT_INDEX {
68                let sibling_index = node_index ^ 1;
69                node_can_be_computed.insert(node_index);
70                node_is_needed.insert(sibling_index);
71                node_index /= 2;
72            }
73        }
74
75        let set_difference = node_is_needed.difference(&node_can_be_computed).copied();
76        let set_union = node_is_needed
77            .union(&node_can_be_computed)
78            .sorted_unstable()
79            .rev();
80
81        let mut set_union = set_union.peekable();
82
83        let mut set_union_as_ordered_pairs = Vec::new();
84        while set_union.peek().is_some() {
85            let right_index = *set_union.next().unwrap();
86
87            // Crashes on odd-length of input list, which is what we want, as
88            // this acts as a sanity check.
89            let left_index = *set_union.next().unwrap();
90            set_union_as_ordered_pairs.push((left_index, right_index));
91        }
92
93        (
94            set_difference.sorted_unstable().rev().collect(),
95            set_union_as_ordered_pairs,
96        )
97    }
98
99    /// Calculate a root from an authentication structure, indexed leafs, and
100    /// additional witness data on `self`. Crashes if the witness data is
101    /// incorrect and if the list of indexed leafs is empty.
102    pub fn root_from_authentication_struct(
103        &self,
104        tree_height: u32,
105        auth_struct: Vec<Digest>,
106        indexed_leafs: Vec<(u64, Digest)>,
107    ) -> Digest {
108        fn digest_to_xfe(digest: Digest, challenge: XFieldElement) -> XFieldElement {
109            let leaf_xfe_lo = XFieldElement::new([digest.0[0], digest.0[1], digest.0[2]]);
110            let leaf_xfe_hi =
111                challenge * XFieldElement::new([digest.0[3], digest.0[4], BFieldElement::one()]);
112
113            leaf_xfe_lo + leaf_xfe_hi
114        }
115
116        fn node_index_to_bfe(node_index: u64) -> BFieldElement {
117            BFieldElement::new(node_index)
118        }
119
120        // Sanity check
121        assert_eq!(
122            self.nd_auth_struct_indices.len(),
123            auth_struct.len(),
124            "Provided auth struct length must match that specified in receiver"
125        );
126
127        // Get challenges
128        let (alpha, beta, gamma) = {
129            let mut sponge = Tip5::init();
130            sponge.pad_and_absorb_all(&indexed_leafs.encode());
131            sponge.pad_and_absorb_all(&auth_struct.encode());
132            let challenges = sponge.sample_scalars(3);
133            (challenges[0], challenges[1], challenges[2])
134        };
135
136        // Accumulate `p` from public data
137        let mut p = XFieldElement::one();
138        for i in (0..indexed_leafs.len()).rev() {
139            let node_index_as_bfe = node_index_to_bfe((1 << tree_height) ^ indexed_leafs[i].0);
140            let leaf_as_xfe = digest_to_xfe(indexed_leafs[i].1, alpha);
141            let fact = leaf_as_xfe - beta + gamma * node_index_as_bfe;
142            p *= fact;
143        }
144
145        let mut prev = 0;
146        for i in (0..auth_struct.len()).rev() {
147            let auth_struct_index = self.nd_auth_struct_indices[i];
148
149            // `auth_struct` must be sorted high-to-low by node-index. But since
150            // we're traversing in reverse order, the inequality is flipped.
151            assert!(auth_struct_index > prev);
152            prev = auth_struct_index;
153
154            let auth_struct_index_as_bfe = node_index_to_bfe(auth_struct_index);
155
156            let auth_str_elem_as_xfe = digest_to_xfe(auth_struct[i], alpha);
157            let fact = auth_str_elem_as_xfe - beta + gamma * auth_struct_index_as_bfe;
158            p *= fact;
159        }
160
161        // Use secret data to invert `p` back and to calculate the root
162        let mut t = indexed_leafs.first().unwrap().1;
163        let mut t_xfe = digest_to_xfe(t, alpha);
164        let mut parent_index_bfe = BFieldElement::one();
165        for ((l, r), (left_index, right_index)) in self
166            .nd_siblings
167            .iter()
168            .zip_eq(self.nd_sibling_indices.clone())
169        {
170            let left_index_bfe = node_index_to_bfe(left_index);
171            let right_index_bfe = node_index_to_bfe(right_index);
172            assert_eq!(left_index + 1, right_index);
173            parent_index_bfe = left_index_bfe / bfe!(2);
174
175            t = Tip5::hash_pair(*l, *r);
176
177            let l_xfe = digest_to_xfe(*l, alpha);
178            let r_xfe = digest_to_xfe(*r, alpha);
179            t_xfe = digest_to_xfe(t, alpha);
180
181            let fact_left = l_xfe - beta + gamma * left_index_bfe;
182            let fact_right = r_xfe - beta + gamma * right_index_bfe;
183            let fact_parent = t_xfe - beta + gamma * parent_index_bfe;
184
185            p *= fact_left.inverse() * fact_right.inverse() * fact_parent;
186        }
187
188        assert_eq!(t_xfe - beta + gamma, p);
189
190        assert!(parent_index_bfe.is_one());
191
192        t
193    }
194
195    /// Return the authentication structure authenticity witness,
196    /// authentication structure, and the (leaf-index, leaf-digest) pairs
197    /// from a list of MMR membership proofs. All MMR membership proofs must
198    /// belong under the same peak, i.e., be part of the same Merkle tree in
199    /// the list of Merkle trees that the MMR contains.
200    ///
201    /// Panics if the input list of MMR-membership proofs is empty, or if they
202    /// do not all belong under the same peak.
203    pub fn new_from_mmr_membership_proofs(
204        mmra: &MmrAccumulator,
205        indexed_mmr_mps: Vec<(u64, Digest, MmrMembershipProof)>,
206    ) -> HashMap<u32, AuthenticatedMerkleAuthStruct> {
207        #[derive(Clone, Debug)]
208        struct IndexedAuthenticatedMmrLeaf {
209            merkle_tree_node_index: u64,
210            merkle_tree_leaf_index: u64,
211            leaf_digest: Digest,
212            membership_proof: MmrMembershipProof,
213        }
214
215        // Split indexed MMR-mps into a hashmap with one entry for each
216        // referenced peak in the MMR.
217        let num_mmr_leafs = mmra.num_leafs();
218        let mut peak_index_to_indexed_mmr_mp: HashMap<u32, Vec<IndexedAuthenticatedMmrLeaf>> =
219            HashMap::default();
220        let peak_heights = get_peak_heights(num_mmr_leafs);
221        for (mmr_leaf_index, leaf, mmr_mp) in indexed_mmr_mps {
222            let (mt_index, peak_index) =
223                leaf_index_to_mt_index_and_peak_index(mmr_leaf_index, num_mmr_leafs);
224            let peak_index_as_usize: usize = peak_index.try_into().unwrap();
225            let num_leafs_local_mt = 1 << peak_heights[peak_index_as_usize];
226            let mt_leaf_index = mt_index - num_leafs_local_mt;
227            peak_index_to_indexed_mmr_mp
228                .entry(peak_index)
229                .or_default()
230                .push(IndexedAuthenticatedMmrLeaf {
231                    merkle_tree_node_index: mt_index,
232                    merkle_tree_leaf_index: mt_leaf_index,
233                    leaf_digest: leaf,
234                    membership_proof: mmr_mp,
235                });
236        }
237
238        // Loop over all peaks and collect an authentication witness struct
239        // for each peak.
240        let mut peak_index_to_authenticated_auth_struct = HashMap::default();
241        for (peak_index, indexed_mmr_mp_structs) in peak_index_to_indexed_mmr_mp {
242            let peak_index_as_usize: usize = peak_index.try_into().unwrap();
243            let num_leafs_in_local_mt = 1 << peak_heights[peak_index_as_usize];
244            let local_mt_leaf_indices = indexed_mmr_mp_structs
245                .iter()
246                .map(|x| x.merkle_tree_leaf_index)
247                .collect_vec();
248
249            let (nd_auth_struct_indices, nd_sibling_indices) =
250                Self::auth_struct_and_nd_indices(num_leafs_in_local_mt, &local_mt_leaf_indices);
251            let peak = mmra.peaks()[peak_index_as_usize];
252
253            let mut node_digests: HashMap<u64, Digest> = HashMap::default();
254            node_digests.insert(ROOT_MT_INDEX, peak);
255
256            // Loop over all indexed leafs for this peak
257            for indexed_mmr_mp in indexed_mmr_mp_structs.iter() {
258                let mut mt_node_index = indexed_mmr_mp.merkle_tree_node_index;
259                let mut node = indexed_mmr_mp.leaf_digest;
260
261                // Loop over all authentication path elements for this indexed leaf
262                for ap_elem in indexed_mmr_mp.membership_proof.authentication_path.iter() {
263                    node_digests.insert(mt_node_index, node);
264                    node_digests.insert(mt_node_index ^ 1, *ap_elem);
265                    node = if mt_node_index & 1 == 0 {
266                        Tip5::hash_pair(node, *ap_elem)
267                    } else {
268                        Tip5::hash_pair(*ap_elem, node)
269                    };
270
271                    mt_node_index /= 2;
272                }
273
274                // Sanity check that MMR-MPs are valid
275                assert_eq!(peak, node, "Derived peak must match provided peak");
276            }
277            let nd_siblings = nd_sibling_indices
278                .iter()
279                .map(|(left_idx, right_idx)| (node_digests[left_idx], node_digests[right_idx]))
280                .collect_vec();
281            let auth_struct = nd_auth_struct_indices
282                .iter()
283                .map(|idx| node_digests[idx])
284                .collect_vec();
285            let indexed_leafs = indexed_mmr_mp_structs
286                .into_iter()
287                .map(|indexed_mmr_mp| {
288                    (
289                        indexed_mmr_mp.merkle_tree_leaf_index,
290                        indexed_mmr_mp.leaf_digest,
291                    )
292                })
293                .collect_vec();
294
295            let witness = Self {
296                nd_auth_struct_indices,
297                nd_sibling_indices,
298                nd_siblings,
299            };
300
301            peak_index_to_authenticated_auth_struct.insert(
302                peak_index,
303                AuthenticatedMerkleAuthStruct {
304                    auth_struct,
305                    indexed_leafs,
306                    witness,
307                },
308            );
309        }
310
311        peak_index_to_authenticated_auth_struct
312    }
313
314    /// Return the authentication structure witness, authentication structure,
315    /// and the (leaf-index, leaf-digest) pairs.
316    pub fn new_from_merkle_tree(
317        tree: &MerkleTree,
318        mut revealed_leaf_indices: Vec<u64>,
319    ) -> AuthenticatedMerkleAuthStruct {
320        revealed_leaf_indices.sort_unstable();
321        revealed_leaf_indices.dedup();
322        revealed_leaf_indices.reverse();
323        let num_leafs: u64 = tree.num_leafs() as u64;
324
325        let (nd_auth_struct_indices, nd_sibling_indices) =
326            Self::auth_struct_and_nd_indices(num_leafs, &revealed_leaf_indices);
327
328        let nd_siblings = nd_sibling_indices
329            .iter()
330            .map(|&(l, r)| {
331                let l: usize = l.try_into().unwrap();
332                let r: usize = r.try_into().unwrap();
333                (tree.node(l).unwrap(), tree.node(r).unwrap())
334            })
335            .collect_vec();
336
337        let revealed_leafs = revealed_leaf_indices
338            .iter()
339            .map(|j| tree.node((*j + num_leafs) as usize).unwrap())
340            .collect_vec();
341        let indexed_leafs = revealed_leaf_indices
342            .clone()
343            .into_iter()
344            .zip_eq(revealed_leafs)
345            .collect_vec();
346
347        let auth_struct = nd_auth_struct_indices
348            .iter()
349            .map(|node_index| tree.node(*node_index as usize).unwrap())
350            .collect_vec();
351
352        let witness = Self {
353            nd_auth_struct_indices,
354            nd_sibling_indices,
355            nd_siblings,
356        };
357
358        AuthenticatedMerkleAuthStruct {
359            auth_struct,
360            indexed_leafs,
361            witness,
362        }
363    }
364}
365
366#[cfg(test)]
367mod tests {
368    use proptest::collection::vec;
369    use proptest::prop_assert_eq;
370    use rand::random;
371    use test_strategy::proptest;
372
373    use super::*;
374    use crate::twenty_first::math::other::random_elements;
375    use crate::twenty_first::util_types::mmr::mmr_accumulator::util::mmra_with_mps;
376
377    #[proptest(cases = 20)]
378    fn root_from_authentication_struct_mmr_prop_test(
379        #[strategy(0..u64::MAX / 2)] mmr_leaf_count: u64,
380        #[strategy(0usize..20)] _num_revealed_leafs: usize,
381        #[strategy(vec(0u64..#mmr_leaf_count, #_num_revealed_leafs))]
382        mmr_revealed_leaf_indices: Vec<u64>,
383    ) {
384        let indexed_leafs_input: Vec<(u64, Digest)> = mmr_revealed_leaf_indices
385            .iter()
386            .map(|idx| (*idx, random()))
387            .collect_vec();
388        let (mmra, mmr_mps) = mmra_with_mps(mmr_leaf_count, indexed_leafs_input.clone());
389        let indexed_mmr_mps = mmr_mps
390            .into_iter()
391            .zip_eq(indexed_leafs_input)
392            .map(|(mmr_mp, (idx, leaf))| (idx, leaf, mmr_mp))
393            .collect_vec();
394
395        let authenticated_auth_structs =
396            AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps);
397
398        let peak_heights = get_peak_heights(mmr_leaf_count);
399        for (peak_index, authentication_auth_struct) in authenticated_auth_structs {
400            let AuthenticatedMerkleAuthStruct {
401                auth_struct,
402                indexed_leafs,
403                witness,
404            } = &authentication_auth_struct;
405            let tree_height: u32 = peak_heights[peak_index as usize];
406            let computed_root = witness.root_from_authentication_struct(
407                tree_height,
408                auth_struct.to_owned(),
409                indexed_leafs.to_owned(),
410            );
411
412            prop_assert_eq!(mmra.peaks()[peak_index as usize], computed_root);
413        }
414    }
415
416    #[test]
417    fn auth_struct_on_empty_mmr() {
418        let empty_mmra = MmrAccumulator::init(vec![], 0);
419        let authenticated_auth_structs =
420            AuthStructIntegrityProof::new_from_mmr_membership_proofs(&empty_mmra, vec![]);
421        assert!(authenticated_auth_structs.is_empty());
422    }
423
424    #[test]
425    fn auth_struct_non_empty_mmr_empty_leaf_list() {
426        let mmra_10_leafs = MmrAccumulator::new_from_leafs(vec![Digest::default(); 10]);
427        let authenticated_auth_structs =
428            AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra_10_leafs, vec![]);
429        assert!(authenticated_auth_structs.is_empty());
430    }
431
432    #[should_panic]
433    #[test]
434    fn panics_on_missing_nd_digests() {
435        let tree_height = 3u32;
436        let num_leafs = 1u64 << tree_height;
437        let leafs: Vec<Digest> = random_elements(num_leafs.try_into().unwrap());
438        let tree = MerkleTree::par_new(&leafs).unwrap();
439
440        let authenticated_auth_struct =
441            AuthStructIntegrityProof::new_from_merkle_tree(&tree, vec![0]);
442        let AuthenticatedMerkleAuthStruct {
443            auth_struct,
444            indexed_leafs,
445            mut witness,
446        } = authenticated_auth_struct;
447        witness.nd_sibling_indices.clear();
448        witness.nd_siblings.clear();
449
450        witness.root_from_authentication_struct(tree_height, auth_struct, indexed_leafs);
451    }
452
453    #[test]
454    fn auth_struct_from_mmr_mps_test_height_5_9_indices() {
455        let local_tree_height = 5;
456        let mmr_leaf_indices = [0, 1, 2, 16, 17, 18, 27, 29, 31];
457        let indexed_leafs_input: Vec<(u64, Digest)> = mmr_leaf_indices
458            .iter()
459            .map(|idx| (*idx, random()))
460            .collect_vec();
461        let (mmra, mmr_mps) = mmra_with_mps(1 << local_tree_height, indexed_leafs_input.clone());
462        let indexed_mmr_mps = mmr_mps
463            .into_iter()
464            .zip_eq(indexed_leafs_input)
465            .map(|(mmr_mp, (idx, leaf))| (idx, leaf, mmr_mp))
466            .collect_vec();
467
468        let authenticity_witnesses =
469            AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps);
470        assert!(
471            authenticity_witnesses.len().is_one(),
472            "All indices belong to first peak"
473        );
474        let AuthenticatedMerkleAuthStruct {
475            auth_struct,
476            indexed_leafs,
477            witness,
478        } = &authenticity_witnesses[&0];
479
480        let tree_height: u32 = local_tree_height.try_into().unwrap();
481        let computed_root = witness.root_from_authentication_struct(
482            tree_height,
483            auth_struct.to_owned(),
484            indexed_leafs.to_owned(),
485        );
486
487        let peak_index = 0;
488        let expected_root = mmra.peaks()[peak_index];
489        assert_eq!(expected_root, computed_root);
490    }
491
492    #[test]
493    fn auth_struct_from_mmr_mps_test_height_4_2_indices() {
494        let local_tree_height = 4;
495        let mmr_leaf_indices = [0, 1];
496        let indexed_leafs_input: Vec<(u64, Digest)> = mmr_leaf_indices
497            .iter()
498            .map(|idx| (*idx, random()))
499            .collect_vec();
500        let (mmra, mmr_mps) = mmra_with_mps(1 << local_tree_height, indexed_leafs_input.clone());
501        let indexed_mmr_mps = mmr_mps
502            .into_iter()
503            .zip_eq(indexed_leafs_input)
504            .map(|(mmr_mp, (idx, leaf))| (idx, leaf, mmr_mp))
505            .collect_vec();
506
507        let authenticity_witnesses =
508            AuthStructIntegrityProof::new_from_mmr_membership_proofs(&mmra, indexed_mmr_mps);
509        assert!(
510            authenticity_witnesses.len().is_one(),
511            "All indices belong to first peak"
512        );
513        let AuthenticatedMerkleAuthStruct {
514            auth_struct,
515            indexed_leafs,
516            witness,
517        } = &authenticity_witnesses[&0];
518
519        let tree_height: u32 = local_tree_height.try_into().unwrap();
520        let computed_root = witness.root_from_authentication_struct(
521            tree_height,
522            auth_struct.to_owned(),
523            indexed_leafs.to_owned(),
524        );
525
526        let peak_index = 0;
527        let expected_root = mmra.peaks()[peak_index];
528        assert_eq!(expected_root, computed_root);
529    }
530
531    #[proptest(cases = 20)]
532    fn root_from_authentication_struct_prop_test(
533        #[strategy(0..12u64)] tree_height: u64,
534        #[strategy(1usize..100)] _num_revealed_leafs: usize,
535        #[strategy(vec(0u64..1<<#tree_height, #_num_revealed_leafs))] revealed_leaf_indices: Vec<
536            u64,
537        >,
538    ) {
539        let num_leafs = 1u64 << tree_height;
540        let leafs: Vec<Digest> = random_elements(num_leafs.try_into().unwrap());
541        let tree = MerkleTree::par_new(&leafs).unwrap();
542
543        let authenticated_auth_struct =
544            AuthStructIntegrityProof::new_from_merkle_tree(&tree, revealed_leaf_indices);
545        let AuthenticatedMerkleAuthStruct {
546            auth_struct,
547            indexed_leafs,
548            witness,
549        } = authenticated_auth_struct;
550
551        let tree_height: u32 = tree_height.try_into().unwrap();
552        let computed_root =
553            witness.root_from_authentication_struct(tree_height, auth_struct, indexed_leafs);
554        let expected_root = tree.root();
555        prop_assert_eq!(expected_root, computed_root);
556    }
557
558    fn prop_from_merkle_tree(
559        tree_height: usize,
560        leaf_indices: Vec<u64>,
561        nd_auth_struct_indices: Vec<u64>,
562        nd_sibling_indices: Vec<(u64, u64)>,
563    ) {
564        let leafs: Vec<Digest> = random_elements(1 << tree_height);
565        let tree = MerkleTree::par_new(&leafs).unwrap();
566
567        let auth_struct = nd_auth_struct_indices
568            .iter()
569            .map(|i| tree.node(*i as usize).unwrap())
570            .collect_vec();
571        let revealed_leafs = leaf_indices
572            .iter()
573            .map(|i| tree.leaf(*i as usize).unwrap())
574            .collect_vec();
575        let revealed_leafs = leaf_indices
576            .into_iter()
577            .zip_eq(revealed_leafs)
578            .collect_vec();
579        let nd_siblings = nd_sibling_indices
580            .iter()
581            .map(|(left_idx, right_idx)| {
582                (
583                    tree.node(*left_idx as usize).unwrap(),
584                    tree.node(*right_idx as usize).unwrap(),
585                )
586            })
587            .collect_vec();
588
589        let mmr_auth_struct = AuthStructIntegrityProof {
590            nd_auth_struct_indices,
591            nd_sibling_indices,
592            nd_siblings,
593        };
594        let tree_height: u32 = tree_height.try_into().unwrap();
595        let calculated_root = mmr_auth_struct.root_from_authentication_struct(
596            tree_height,
597            auth_struct,
598            revealed_leafs,
599        );
600        assert_eq!(tree.root(), calculated_root);
601    }
602
603    #[test]
604    fn root_from_authentication_struct_tree_height_0_1_revealed() {
605        let tree_height = 0;
606        let leaf_indices = vec![0];
607        let nd_auth_struct_indices = vec![];
608        let nd_sibling_indices = vec![];
609        prop_from_merkle_tree(
610            tree_height,
611            leaf_indices,
612            nd_auth_struct_indices,
613            nd_sibling_indices,
614        )
615    }
616
617    #[test]
618    fn root_from_authentication_struct_tree_height_1_1_revealed() {
619        let tree_height = 1;
620        let leaf_indices = vec![0u64];
621        let nd_auth_struct_indices = vec![3];
622        let nd_sibling_indices = vec![(2u64, 3u64)];
623        prop_from_merkle_tree(
624            tree_height,
625            leaf_indices,
626            nd_auth_struct_indices,
627            nd_sibling_indices,
628        )
629    }
630
631    #[test]
632    fn root_from_authentication_struct_tree_height_1_2_revealed() {
633        let tree_height = 1;
634        let leaf_indices = vec![0u64, 1];
635        let nd_auth_struct_indices = vec![];
636        let nd_sibling_indices = vec![(2u64, 3u64)];
637        prop_from_merkle_tree(
638            tree_height,
639            leaf_indices,
640            nd_auth_struct_indices,
641            nd_sibling_indices,
642        )
643    }
644
645    #[test]
646    fn root_from_authentication_struct_tree_height_2_2_revealed() {
647        let tree_height = 2;
648        let leaf_indices = vec![0u64, 1];
649        let auth_struct_indices = vec![3];
650        let nd_sibling_indices = vec![(4u64, 5u64), (2, 3)];
651        prop_from_merkle_tree(
652            tree_height,
653            leaf_indices,
654            auth_struct_indices,
655            nd_sibling_indices,
656        )
657    }
658
659    #[test]
660    fn root_from_authentication_struct_tree_height_4_4_revealed() {
661        let tree_height = 4;
662        let leaf_indices = vec![14u64, 12, 10, 8];
663        let num_leafs = 1 << tree_height;
664        let auth_struct_indices = vec![
665            num_leafs + 15,
666            num_leafs + 13,
667            num_leafs + 11,
668            num_leafs + 9,
669            2,
670        ];
671        let nd_sibling_indices_layer_height_0 = [(14u64, 15u64), (12, 13), (10, 11), (8, 9)]
672            .map(|(l, r)| (l + num_leafs, r + num_leafs));
673        let nd_sibling_indices_layer_height_1 = [(14u64, 15u64), (12u64, 13u64)];
674        let nd_sibling_indices_layer_height_2 = [(6u64, 7u64)];
675        let nd_sibling_indices_layer_height_3 = [(2u64, 3u64)];
676        let nd_sibling_indices = [
677            nd_sibling_indices_layer_height_0.to_vec(),
678            nd_sibling_indices_layer_height_1.to_vec(),
679            nd_sibling_indices_layer_height_2.to_vec(),
680            nd_sibling_indices_layer_height_3.to_vec(),
681        ]
682        .concat();
683
684        prop_from_merkle_tree(
685            tree_height,
686            leaf_indices,
687            auth_struct_indices,
688            nd_sibling_indices,
689        )
690    }
691}