Skip to main content

nomt_core/proof/
multi_proof.rs

1//! Generate a multiproof from a vector of path proofs.
2//! The multiproof will contain the minimum information needed to verify
3//! the inclusion of all provided path proofs.
4
5use crate::{
6    hasher::NodeHasher,
7    proof::{
8        path_proof::{hash_path, shared_bits},
9        KeyOutOfScope, PathProof, PathProofTerminal,
10    },
11    trie::{InternalData, KeyPath, LeafData, Node, NodeKind, ValueHash, TERMINATOR},
12};
13
14#[cfg(not(feature = "std"))]
15use alloc::{vec, vec::Vec};
16
17use bitvec::prelude::*;
18use core::{cmp::Ordering, ops::Range};
19
20/// This struct includes the terminal node and its depth
21#[derive(Debug, Clone, Eq, PartialEq)]
22#[cfg_attr(
23    feature = "borsh",
24    derive(borsh::BorshDeserialize, borsh::BorshSerialize)
25)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub struct MultiPathProof {
28    /// Terminal node
29    pub terminal: PathProofTerminal,
30    /// Depth of the terminal node
31    pub depth: usize,
32}
33
34/// A proof of multiple paths through the trie.
35#[derive(Debug, Clone, Eq, PartialEq)]
36#[cfg_attr(
37    feature = "borsh",
38    derive(borsh::BorshDeserialize, borsh::BorshSerialize)
39)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub struct MultiProof {
42    /// List of all provable paths. These are sorted in ascending order by bit-path
43    pub paths: Vec<MultiPathProof>,
44    /// Vector containing the minimum number of nodes required
45    /// to reconstruct all other nodes later.
46    ///
47    /// The format is a recursive bisection:
48    /// [upper_siblings ++ left_siblings ++ right_siblings]
49    ///
50    /// upper_siblings could be:
51    /// + siblings shared among all paths in each bisection
52    /// + unique siblings associated with a terminal node
53    ///
54    /// In the latter case, both left and right bisections will be empty
55    ///
56    /// left_siblings is the same format, but applied to all the nodes in the left bisection.
57    /// right_siblings is the same format, but applied to all the nodes in the right bisection.
58    pub siblings: Vec<Node>,
59}
60
61// Given a vector of PathProofs ordered by the key_path,
62// `PathProofRange` represent a range of that vector
63// with key_paths that have common bits up to path_bit_index
64struct PathProofRange {
65    // lower bound of the range
66    lower: usize,
67    // upper bound of the range
68    upper: usize,
69    // bit index in the key path where this struct is pointing at,
70    // this index will be increased or used to create a new bisection
71    path_bit_index: usize,
72}
73
74enum PathProofRangeStep {
75    Bisect {
76        left: PathProofRange,
77        right: PathProofRange,
78    },
79    Advance {
80        sibling: Node,
81    },
82}
83
84impl PathProofRange {
85    fn prove_unique_path_remainder(
86        &self,
87        path_proofs: &[PathProof],
88    ) -> Option<(MultiPathProof, Vec<Node>)> {
89        // If PathProofRange contains only one path_proofs
90        // return a MultiPathProof with all its unique siblings
91        if self.lower != self.upper - 1 {
92            return None;
93        }
94
95        let path_proof = &path_proofs[self.lower];
96        let unique_siblings: Vec<Node> = path_proof
97            .siblings
98            .iter()
99            .skip(self.path_bit_index)
100            .copied()
101            .collect();
102
103        Some((
104            MultiPathProof {
105                terminal: path_proof.terminal.clone(),
106                depth: self.path_bit_index + unique_siblings.len(),
107            },
108            unique_siblings,
109        ))
110    }
111
112    fn step(&mut self, path_proofs: &[PathProof]) -> PathProofRangeStep {
113        // check if at least two key_path in the path_proofs range
114        // has two different bits in position path_bit_index
115        //
116        // they are ordered and all the bits up to path_bit_index
117        // are shared so we can just check if the first and the last one differs
118        let path_lower = path_proofs[self.lower].terminal.path();
119        let path_upper = path_proofs[self.upper - 1].terminal.path();
120
121        if path_lower[self.path_bit_index] != path_upper[self.path_bit_index] {
122            // if they differ we can skip their siblings but we need to bisect the slice
123            //
124            // binary search between key_paths in the slice to see where to
125            // perform the bisection
126            //
127            // UNWRAP: We have just checked that path_lower and path_upper differ at path_bit_index.
128            // Therefore, with the vector of path_proofs ordered, we can be sure that there is at least
129            // one path with its key_path containing a value of 1 at path_bit_index.
130            // Since there is at least one 1 bit and Ordering::Equal is never returned,
131            // the method binary_search_by will always return an Error containing the index
132            // of the first occurrence of one in the key_path.
133            let mid = self.lower
134                + path_proofs[self.lower..self.upper]
135                    .binary_search_by(|path_proof| {
136                        if !path_proof.terminal.path()[self.path_bit_index] {
137                            core::cmp::Ordering::Less
138                        } else {
139                            core::cmp::Ordering::Greater
140                        }
141                    })
142                    .unwrap_err();
143
144            let left = PathProofRange {
145                path_bit_index: self.path_bit_index + 1,
146                lower: self.lower,
147                upper: mid,
148            };
149
150            let right = PathProofRange {
151                path_bit_index: self.path_bit_index + 1,
152                lower: mid,
153                upper: self.upper,
154            };
155
156            PathProofRangeStep::Bisect { left, right }
157        } else {
158            // if they don't differ, we need their sibling
159            let sibling = path_proofs[self.lower].siblings[self.path_bit_index];
160            self.path_bit_index += 1;
161            PathProofRangeStep::Advance { sibling }
162        }
163    }
164}
165
166impl MultiProof {
167    /// Construct a MultiProof from a vector of *ordered* PathProof.
168    ///
169    /// Note that the path proofs produced within a [`crate::witness::Witness`] are not guaranteed
170    /// to be ordered, so the input should be sorted lexicographically by the terminal path prior
171    /// to calling this function.
172    pub fn from_path_proofs(path_proofs: Vec<PathProof>) -> Self {
173        // A multi-proof can be viewed by associating each terminal node
174        // with its first n uniquely related siblings from its path proof,
175        // followed by all necessary siblings that are not derivable from
176        // the previously mentioned siblings.
177
178        // The goal is to traverse the entire tree
179        // formed by all path proofs and only collect the siblings
180        // that cannot be reconstructed in the future
181        //
182        // The traversal does not occur on the siblings themselves,
183        // but on the ordered set of key_paths within PathProofs.
184        //
185        // For example, take two key_paths starting from the first bit.
186        // If two keys share bits up to index i, they will have the same sibling at index i.
187        // If the bit at index i differs, their paths diverge, and no sibling is needed at that index
188        // because it can be reconstructed from siblings collected later in the other key.
189        // When a differing bit is found, each key_path needs separate scanning.
190        //
191        // When there is a single key_path, all siblings are necessary.
192        //
193        // When there are more than two key_paths, the same logic is applied,
194        // but if two key_paths have different bits at an index, the key_paths are split
195        // based on the value at that index.
196        //
197        // If all key_paths share a bit at an index, that sibling is required and it is one
198        // of the siblings mentioned earlier.
199        // If at least two key_paths differ, no sibling is needed, but the key_paths must be divided
200        // based on having bit 0 or 1 at that index.
201        //
202        // Iterate this algorithm on the bisection to determine the minimum necessary siblings.
203        //
204        // `siblings` will follow this structure for each bisection
205        // |common siblings| ext siblings in the left bisection | ext siblings in the right bisection |
206
207        if path_proofs.is_empty() {
208            return MultiProof {
209                paths: Vec::new(),
210                siblings: Vec::new(),
211            };
212        }
213
214        let mut paths: Vec<MultiPathProof> = vec![];
215        let mut siblings: Vec<Node> = vec![];
216
217        // initially we're looking at all the path_proofs
218        let mut proof_range = PathProofRange {
219            path_bit_index: 0,
220            lower: 0,
221            upper: path_proofs.len(),
222        };
223
224        // Common siblings encountered while stepping through PathProofRange
225        let mut common_siblings: Vec<Node> = vec![];
226
227        // stack used to handle bfs through PathProofRanges
228        let mut stack: Vec<PathProofRange> = vec![];
229
230        loop {
231            // check if proof_range represents a unique path proof
232            if let Some((sub_path_proof, unique_siblings)) =
233                proof_range.prove_unique_path_remainder(&path_proofs)
234            {
235                paths.push(sub_path_proof);
236                siblings.extend(unique_siblings);
237
238                // sub_path_proof always immediately follows a bisection in a well-formed trie
239                assert!(common_siblings.is_empty());
240
241                // skip to the next bisection in the stack, if empty we're finished
242                proof_range = match stack.pop() {
243                    Some(v) => v,
244                    None => break,
245                };
246                continue;
247            }
248
249            // Step through the proof_range, it could result in a bisection,
250            // or the index of the key_path is moved forward producing a new
251            // sibling of the current sub tree
252            match proof_range.step(&path_proofs) {
253                PathProofRangeStep::Bisect { left, right } => {
254                    // insert collected common siblings
255                    siblings.extend(common_siblings.drain(..));
256
257                    // push into the stack the right Bisection and work on the left one
258                    proof_range = left;
259                    stack.push(right);
260                }
261                PathProofRangeStep::Advance { sibling } => common_siblings.push(sibling),
262            };
263        }
264
265        Self { paths, siblings }
266    }
267}
268
269/// Errors in multi-proof verification.
270#[derive(Debug, Clone, Copy, PartialEq, Eq)]
271pub enum MultiProofVerificationError {
272    /// Root hash mismatched at the end of the verification.
273    RootMismatch,
274    /// Multi-proof paths were provided out of order.
275    PathsOutOfOrder,
276    /// Extra siblings were provided.
277    TooManySiblings,
278}
279
280#[derive(Debug, Clone)]
281struct VerifiedMultiPath {
282    terminal: PathProofTerminal,
283    depth: usize,
284    unique_siblings: Range<usize>,
285}
286
287// indicates a bisection which started at a given depth and covers these common siblings.
288#[derive(Debug, Clone)]
289struct VerifiedBisection {
290    start_depth: usize,
291    common_siblings: Range<usize>,
292}
293
294/// A verified multi-proof.
295#[derive(Debug, Clone)]
296#[must_use = "VerifiedMultiProof only checks the consistency of the trie, not the values"]
297pub struct VerifiedMultiProof {
298    inner: Vec<VerifiedMultiPath>,
299    bisections: Vec<VerifiedBisection>,
300    siblings: Vec<Node>,
301    root: Node,
302}
303
304impl VerifiedMultiProof {
305    /// Find the index of the path contained in this multi-proof, if any, which would prove
306    /// the given key.
307    ///
308    /// Runtime is O(log(n)) in the number of paths this multi-proof contains.
309    pub fn find_index_for(&self, key_path: &KeyPath) -> Result<usize, KeyOutOfScope> {
310        let search_result = self.inner.binary_search_by(|v| {
311            v.terminal.path()[..v.depth].cmp(&key_path.view_bits::<Msb0>()[..v.depth])
312        });
313
314        search_result.map_err(|_| KeyOutOfScope)
315    }
316
317    /// Check whether this proves that a key has no value in the trie.
318    /// Runtime is O(log(n)) in the number of paths this multi-proof contains.
319    ///
320    /// A return value of `Ok(true)` confirms that the key indeed has no value in the trie.
321    /// A return value of `Ok(false)` means that the key definitely exists within the trie.
322    ///
323    /// Fails if the key is out of the scope of this proof.
324    pub fn confirm_nonexistence(&self, key_path: &KeyPath) -> Result<bool, KeyOutOfScope> {
325        let index = self.find_index_for(key_path)?;
326        Ok(self.confirm_nonexistence_inner(key_path, index))
327    }
328
329    /// Check whether this proves that a key has no value in the trie.
330    /// Runtime is O(log(n)) in the number of paths this multi-proof contains.
331    ///
332    /// A return value of `Ok(true)` confirms that this key indeed has this value in the trie.
333    /// A return value of `Ok(false)` means that this key has a different value or does not exist.
334    ///
335    /// Fails if the key is out of the scope of this proof.
336    pub fn confirm_value(&self, expected_leaf: &LeafData) -> Result<bool, KeyOutOfScope> {
337        let index = self.find_index_for(&expected_leaf.key_path)?;
338        Ok(self.confirm_value_inner(&expected_leaf, index))
339    }
340
341    /// Check whether the specific path with index `index` proves that a key has no value in
342    /// the trie.
343    /// Runtime is O(1).
344    ///
345    /// A return value of `Ok(true)` confirms that the key indeed has no value in the trie.
346    /// A return value of `Ok(false)` means that the key definitely exists within the trie.
347    ///
348    /// Fails if the key is out of the scope of this path.
349    ///
350    /// # Panics
351    ///
352    /// Panics if the index is out-of-bounds.
353    pub fn confirm_nonexistence_with_index(
354        &self,
355        key_path: &KeyPath,
356        index: usize,
357    ) -> Result<bool, KeyOutOfScope> {
358        let path = &self.inner[index];
359        let depth = path.depth;
360        let in_scope = path.terminal.path()[..depth] == key_path.view_bits::<Msb0>()[..depth];
361
362        if in_scope {
363            Ok(self.confirm_nonexistence_inner(key_path, index))
364        } else {
365            Err(KeyOutOfScope)
366        }
367    }
368
369    /// Check whether this proves that a key has no value in the trie.
370    /// Runtime is O(1).
371    ///
372    /// A return value of `Ok(true)` confirms that this key indeed has this value in the trie.
373    /// A return value of `Ok(false)` means that this key has a different value or does not exist
374    /// in the trie.
375    ///
376    /// Fails if the key is out of the scope of this path.
377    ///
378    /// # Panics
379    ///
380    /// Panics if the index is out-of-bounds.
381    pub fn confirm_value_with_index(
382        &self,
383        expected_leaf: &LeafData,
384        index: usize,
385    ) -> Result<bool, KeyOutOfScope> {
386        let path = &self.inner[index];
387        let depth = path.depth;
388        let in_scope =
389            path.terminal.path()[..depth] == expected_leaf.key_path.view_bits::<Msb0>()[..depth];
390
391        if in_scope {
392            Ok(self.confirm_value_inner(&expected_leaf, index))
393        } else {
394            Err(KeyOutOfScope)
395        }
396    }
397
398    // assume in-scope
399    fn confirm_nonexistence_inner(&self, key_path: &KeyPath, index: usize) -> bool {
400        match self.inner[index].terminal {
401            PathProofTerminal::Terminator(_) => true,
402            PathProofTerminal::Leaf(ref leaf_data) => &leaf_data.key_path != key_path,
403        }
404    }
405
406    // assume in-scope
407    fn confirm_value_inner(&self, expected_leaf: &LeafData, index: usize) -> bool {
408        match self.inner[index].terminal {
409            PathProofTerminal::Terminator(_) => false,
410            PathProofTerminal::Leaf(ref leaf_data) => leaf_data == expected_leaf,
411        }
412    }
413}
414
415/// Verify a multi-proof against an expected root. This ONLY checks the consistency of the trie.
416///
417/// You MUST use `confirm_value` or `confirm_nonexistence` to check the values in the verified
418/// multi-proof.
419pub fn verify<H: NodeHasher>(
420    multi_proof: &MultiProof,
421    root: Node,
422) -> Result<VerifiedMultiProof, MultiProofVerificationError> {
423    let mut verified_paths = Vec::with_capacity(multi_proof.paths.len());
424    let mut verified_bisections = Vec::new();
425    for i in 0..multi_proof.paths.len() {
426        let path = &multi_proof.paths[i];
427        if i > 0 {
428            if path.terminal.path() <= multi_proof.paths[i - 1].terminal.path() {
429                return Err(MultiProofVerificationError::PathsOutOfOrder);
430            }
431        }
432    }
433
434    let (new_root, siblings_used) = verify_range::<H>(
435        0,
436        &multi_proof.paths,
437        &multi_proof.siblings,
438        0,
439        &mut verified_paths,
440        &mut verified_bisections,
441    )?;
442
443    if root != new_root {
444        return Err(MultiProofVerificationError::RootMismatch);
445    }
446
447    if siblings_used != multi_proof.siblings.len() {
448        return Err(MultiProofVerificationError::TooManySiblings);
449    }
450
451    Ok(VerifiedMultiProof {
452        inner: verified_paths,
453        bisections: verified_bisections,
454        siblings: multi_proof.siblings.clone(),
455        root: root,
456    })
457}
458
459// returns the node made by verifying this range along with the number of siblings used.
460fn verify_range<H: NodeHasher>(
461    start_depth: usize,
462    paths: &[MultiPathProof],
463    siblings: &[Node],
464    sibling_offset: usize,
465    verified_paths: &mut Vec<VerifiedMultiPath>,
466    verified_bisections: &mut Vec<VerifiedBisection>,
467) -> Result<(Node, usize), MultiProofVerificationError> {
468    // the range should never be empty except in the first call, if the entire multi-proof is
469    // empty.
470    if paths.is_empty() {
471        verified_paths.push(VerifiedMultiPath {
472            terminal: PathProofTerminal::Terminator(crate::trie_pos::TriePosition::new()),
473            depth: 0,
474            unique_siblings: Range { start: 0, end: 0 },
475        });
476        return Ok((TERMINATOR, 0));
477    }
478    if paths.len() == 1 {
479        // at a terminal node, 'siblings' will contain all unique
480        // nodes, hash them up, and return that
481        let terminal_path = &paths[0];
482        let unique_len = terminal_path.depth - start_depth;
483
484        let node = hash_path::<H>(
485            terminal_path.terminal.node::<H>(),
486            &terminal_path.terminal.path()[start_depth..start_depth + unique_len],
487            siblings[..unique_len].iter().rev().copied(),
488        );
489
490        verified_paths.push(VerifiedMultiPath {
491            terminal: terminal_path.terminal.clone(),
492            depth: terminal_path.depth,
493            unique_siblings: Range {
494                start: sibling_offset,
495                end: sibling_offset + unique_len,
496            },
497        });
498
499        return Ok((node, unique_len));
500    }
501
502    let start_path = &paths[0];
503    let end_path = &paths[paths.len() - 1];
504
505    let common_bits = shared_bits(
506        &start_path.terminal.path()[start_depth..],
507        &end_path.terminal.path()[start_depth..],
508    );
509
510    let common_len = start_depth + common_bits;
511    // TODO: if `common_len` == 256 the multi-proof is malformed. error
512
513    let uncommon_start_len = common_len + 1;
514
515    // bisect `paths` by finding the first path which starts with the right bit set.
516    let search_result = paths.binary_search_by(|item| {
517        if !item.terminal.path()[uncommon_start_len - 1] {
518            Ordering::Less
519        } else {
520            Ordering::Greater
521        }
522    });
523
524    // UNWRAP: always `Err` because we never return Ordering::Equal
525    // index always in-bounds because `end_path` has the significant bit set to 1
526    // furthermore, the left and right slices must be non-empty because start/end exist and the
527    // bisection is based off of them.
528    let bisect_idx = search_result.unwrap_err();
529
530    if common_bits > 0 {
531        verified_bisections.push(VerifiedBisection {
532            start_depth,
533            common_siblings: Range {
534                start: sibling_offset,
535                end: sibling_offset + common_bits,
536            },
537        });
538    }
539
540    // recurse into the left bisection.
541    let (left_node, left_siblings_used) = verify_range::<H>(
542        uncommon_start_len,
543        &paths[..bisect_idx],
544        &siblings[common_bits..],
545        sibling_offset + common_bits,
546        verified_paths,
547        verified_bisections,
548    )?;
549
550    // now that we know how many siblings were used on the left, we can recurse into the right.
551    let (right_node, right_siblings_used) = verify_range::<H>(
552        uncommon_start_len,
553        &paths[bisect_idx..],
554        &siblings[common_bits + left_siblings_used..],
555        sibling_offset + common_bits + left_siblings_used,
556        verified_paths,
557        verified_bisections,
558    )?;
559
560    let total_siblings_used = common_bits + left_siblings_used + right_siblings_used;
561    // hash up the internal node composed of left/right, then repeatedly apply common siblings.
562    let node = hash_path::<H>(
563        H::hash_internal(&InternalData {
564            left: left_node,
565            right: right_node,
566        }),
567        &start_path.terminal.path()[start_depth..common_len], // == last_path.same...
568        siblings[..common_bits].iter().rev().copied(),
569    );
570    Ok((node, total_siblings_used))
571}
572
573/// Errors that can occur when verifying an update against a [`VerifiedMultiProof`].
574#[derive(Debug, Clone, Copy)]
575pub enum MultiVerifyUpdateError {
576    /// The operations on the trie were provided out-of-order by [`KeyPath`].
577    OpsOutOfOrder,
578    /// An operation was out of scope for the [`VerifiedMultiProof`]
579    OpOutOfScope,
580    /// Paths were verified against different state-roots.
581    RootMismatch,
582    /// Two terminal paths were provided, where one is a prefix of another.
583    PathPrefixOfAnother,
584}
585
586fn terminal_contains(terminal: &VerifiedMultiPath, key_path: &KeyPath) -> bool {
587    key_path.view_bits::<Msb0>()[..terminal.depth] == terminal.terminal.path()[..terminal.depth]
588}
589
590// walks a multiproof left-to-right and keeps track of a stack of all siblings, based on
591// bisections.
592//
593// when this has ingested all paths up to and including X, the stack will represent all non-unique
594// siblings for X.
595#[derive(Debug)]
596struct CommonSiblings {
597    bisection_stack: Vec<VerifiedBisection>,
598    stack: Vec<(usize, Node)>,
599    taken_siblings: usize,
600    terminal_index: usize,
601    bisection_index: usize,
602}
603
604impl CommonSiblings {
605    fn new() -> Self {
606        CommonSiblings {
607            bisection_stack: Vec::new(),
608            stack: Vec::new(),
609            taken_siblings: 0,
610            terminal_index: 0,
611            bisection_index: 0,
612        }
613    }
614
615    fn advance(&mut self, proof: &VerifiedMultiProof) {
616        let next_terminal = &proof.inner[self.terminal_index];
617
618        let mut prune = true;
619        while next_terminal.unique_siblings.start != self.taken_siblings {
620            let next_bisection = &proof.bisections[self.bisection_index];
621            self.bisection_index += 1;
622
623            assert_eq!(next_bisection.common_siblings.start, self.taken_siblings);
624            if prune {
625                self.pop_to(next_bisection.start_depth);
626                prune = false;
627            }
628
629            // a bisection at depth N involves siblings starting at N+1
630            self.extend(
631                next_bisection.start_depth + 1,
632                next_bisection.common_siblings.end,
633                &proof.siblings,
634            );
635            self.bisection_stack.push(next_bisection.clone());
636        }
637
638        let terminal_n = next_terminal.unique_siblings.end - next_terminal.unique_siblings.start;
639        self.extend(
640            next_terminal.depth - terminal_n + 1,
641            next_terminal.unique_siblings.end,
642            &proof.siblings,
643        );
644        self.terminal_index += 1;
645    }
646
647    fn pop_to(&mut self, depth: usize) {
648        while self
649            .bisection_stack
650            .last()
651            .map_or(false, |b| b.start_depth >= depth)
652        {
653            let _ = self.bisection_stack.pop();
654        }
655
656        while self.stack.last().map_or(false, |(d, _)| *d >= depth) {
657            let _ = self.stack.pop();
658        }
659    }
660
661    fn extend(&mut self, start_depth: usize, end: usize, siblings: &[Node]) {
662        for (i, sibling) in siblings[self.taken_siblings..end].iter().enumerate() {
663            self.stack.push((start_depth + i, *sibling))
664        }
665
666        self.taken_siblings = end;
667    }
668
669    fn pop_if_at_depth(&mut self, depth: usize) -> Option<Node> {
670        if self.stack.last().map_or(false, |(d, _)| *d == depth) {
671            self.stack.pop().map(|(_, n)| n)
672        } else {
673            None
674        }
675    }
676}
677
678/// Verify an update operation against a verified multi-proof. This follows a similar algorithm to
679/// the multi-item update, but without altering any backing storage.
680///
681/// `ops` should contain all updates to be processed. It should be sorted (ascending) by keypath,
682/// without duplicates.
683///
684/// All provided operations should have a key-path which is in scope for the multi proof.
685///
686/// Returns the root of the trie obtained after application of the given updates in the `paths`
687/// vector. In case the `paths` is empty, `prev_root` is returned.
688pub fn verify_update<H: NodeHasher>(
689    proof: &VerifiedMultiProof,
690    ops: Vec<(KeyPath, Option<ValueHash>)>,
691) -> Result<Node, MultiVerifyUpdateError> {
692    if ops.is_empty() {
693        return Ok(proof.root);
694    }
695
696    // left frontier
697    let mut pending_siblings: Vec<(Node, usize)> = Vec::new();
698
699    let mut last_key = None;
700    let mut last_terminal_index = None;
701    let mut next_pending_terminal_index = None;
702
703    let mut working_ops = Vec::new();
704
705    let mut common_siblings = CommonSiblings::new();
706    let ops_len = ops.len();
707
708    // chain with dummy item for handling the last batch.
709    for (i, (key, op)) in ops.into_iter().chain(Some(([0u8; 32], None))).enumerate() {
710        let is_last = i == ops_len;
711
712        if is_last {
713            let updated_terminal_index = last_terminal_index.unwrap_or(0);
714            let start = next_pending_terminal_index.unwrap_or(0);
715
716            // ingest all terminals from the next one needing an update to the end.
717            for terminal_index in start..proof.inner.len() {
718                let next = if terminal_index == proof.inner.len() - 1 {
719                    None
720                } else {
721                    Some(terminal_index + 1)
722                };
723
724                let terminal = &proof.inner[terminal_index];
725                let next_terminal = next.map(|n| &proof.inner[n]);
726
727                let ops = if terminal_index == updated_terminal_index {
728                    &working_ops[..]
729                } else {
730                    &[]
731                };
732
733                common_siblings.advance(&proof);
734                hash_and_compact_terminal::<H>(
735                    &mut pending_siblings,
736                    terminal,
737                    next_terminal,
738                    &mut common_siblings,
739                    ops,
740                )?;
741            }
742        } else {
743            // enforce key ordering.
744            if let Some(last_key) = last_key {
745                if key <= last_key {
746                    return Err(MultiVerifyUpdateError::OpsOutOfOrder);
747                }
748            }
749            last_key = Some(key);
750
751            // find terminal index for the operation, erroring if out of scope.
752            let mut next_terminal_index = last_terminal_index.unwrap_or(0);
753            if proof.inner.len() <= next_terminal_index {
754                return Err(MultiVerifyUpdateError::OpOutOfScope);
755            }
756
757            while !terminal_contains(&proof.inner[next_terminal_index], &key) {
758                next_terminal_index += 1;
759                if proof.inner.len() <= next_terminal_index {
760                    return Err(MultiVerifyUpdateError::OpOutOfScope);
761                }
762            }
763
764            // if this is either the first op or this has the same terminal as the previous op...
765            if last_terminal_index.map_or(true, |x| x == next_terminal_index) {
766                last_terminal_index = Some(next_terminal_index);
767                working_ops.push((key, op));
768                continue;
769            }
770
771            // UNWRAP: guaranteed by above.
772            let updated_index = last_terminal_index.unwrap();
773            last_terminal_index = Some(next_terminal_index);
774
775            // ingest all terminals up to current.
776            let start = next_pending_terminal_index.unwrap_or(0);
777
778            for terminal_index in start..updated_index {
779                let terminal = &proof.inner[terminal_index];
780                let next_terminal = Some(&proof.inner[terminal_index + 1]);
781
782                common_siblings.advance(&proof);
783                hash_and_compact_terminal::<H>(
784                    &mut pending_siblings,
785                    terminal,
786                    next_terminal,
787                    &mut common_siblings,
788                    &[],
789                )?;
790            }
791
792            // ingest the currently updated terminal.
793            let ops = core::mem::replace(&mut working_ops, Vec::new());
794            working_ops.push((key, op));
795
796            let terminal = &proof.inner[updated_index];
797            let next_terminal = proof.inner.get(updated_index + 1);
798            common_siblings.advance(&proof);
799
800            hash_and_compact_terminal::<H>(
801                &mut pending_siblings,
802                terminal,
803                next_terminal,
804                &mut common_siblings,
805                &ops,
806            )?;
807
808            next_pending_terminal_index = Some(updated_index + 1);
809        };
810    }
811
812    // UNWRAP: This is always full unless the update is empty
813    Ok(pending_siblings.pop().map(|n| n.0).unwrap_or(proof.root))
814}
815
816fn hash_and_compact_terminal<H: NodeHasher>(
817    pending_siblings: &mut Vec<(Node, usize)>,
818    terminal: &VerifiedMultiPath,
819    next_terminal: Option<&VerifiedMultiPath>,
820    common_siblings: &mut CommonSiblings,
821    ops: &[(KeyPath, Option<ValueHash>)],
822) -> Result<(), MultiVerifyUpdateError> {
823    let leaf = terminal.terminal.as_leaf_option();
824    let skip = terminal.depth;
825
826    let up_layers = if let Some(next_terminal) = next_terminal {
827        let n = shared_bits(terminal.terminal.path(), next_terminal.terminal.path());
828
829        // SANITY: this is impossible in a well-formed input but we catch it as an error.
830        // The reason this is impossible is because no terminal should be a prefix of another
831        // terminal (by definition)
832        if n == skip {
833            return Err(MultiVerifyUpdateError::PathPrefixOfAnother);
834        }
835
836        // n always < skip
837        // we want to end at layer n + 1
838        skip - (n + 1)
839    } else {
840        skip // go to root
841    };
842
843    let ops = crate::update::leaf_ops_spliced(leaf, &ops);
844    let sub_root = crate::update::build_trie::<H>(skip, ops, |_| {});
845
846    let mut cur_node = sub_root;
847    let mut cur_layer = skip;
848    let end_layer = skip - up_layers;
849
850    // iterate siblings up to the point of collision with next path, replacing with pending
851    // siblings, and compacting where possible.
852    // push (node, end_layer) to pending siblings when done.
853    for bit in terminal.terminal.path()[..terminal.depth]
854        .iter()
855        .by_vals()
856        .rev()
857        .take(up_layers)
858    {
859        let sibling = if pending_siblings.last().map_or(false, |p| p.1 == cur_layer) {
860            // is this even possible? maybe not. but being extra cautious...
861            let _ = common_siblings.pop_if_at_depth(cur_layer);
862            // UNWRAP: guaranteed to exist.
863            pending_siblings.pop().unwrap().0
864        } else {
865            // UNWRAP: `common_siblings` holds everything which isn't computed dynamically from branch
866            // to branch. basically, it's the inverse of `pending_siblings`. so if the sibling isn't
867            // in pending_siblings, it's in here.
868            common_siblings.pop_if_at_depth(cur_layer).unwrap()
869        };
870
871        match (NodeKind::of::<H>(&cur_node), NodeKind::of::<H>(&sibling)) {
872            (NodeKind::Terminator, NodeKind::Terminator) => {}
873            (NodeKind::Leaf, NodeKind::Terminator) => {}
874            (NodeKind::Terminator, NodeKind::Leaf) => {
875                // relocate sibling upwards.
876                cur_node = sibling;
877            }
878            _ => {
879                // otherwise, internal
880                let node_data = if bit {
881                    InternalData {
882                        left: sibling,
883                        right: cur_node,
884                    }
885                } else {
886                    InternalData {
887                        left: cur_node,
888                        right: sibling,
889                    }
890                };
891                cur_node = H::hash_internal(&node_data);
892            }
893        }
894
895        cur_layer -= 1;
896    }
897
898    pending_siblings.push((cur_node, end_layer));
899    Ok(())
900}
901
902#[cfg(test)]
903mod tests {
904    use super::{verify, verify_update, MultiProof};
905
906    use crate::proof::multi_proof::{
907        MultiVerifyUpdateError, VerifiedMultiPath, VerifiedMultiProof,
908    };
909    use crate::{
910        hasher::{Blake3Hasher, NodeHasher},
911        proof::{PathProof, PathProofTerminal},
912        trie::{InternalData, LeafData, ValueHash, TERMINATOR},
913        trie_pos::TriePosition,
914        update::build_trie,
915    };
916    use bitvec::prelude::*;
917    use nomt_test_utils::key_with_prefix;
918
919    #[test]
920    pub fn test_multiproof_creation_single_path_proof() {
921        let mut key_path = [0; 32];
922        key_path[0] = 0b10000000;
923        let sibling1 = [1; 32];
924        let sibling2 = [2; 32];
925        let path_proof = PathProof {
926            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
927                key_path, 256,
928            )),
929            siblings: vec![sibling1, sibling2],
930        };
931
932        let multi_proof = MultiProof::from_path_proofs(vec![path_proof]);
933        assert_eq!(multi_proof.paths.len(), 1);
934        assert_eq!(
935            multi_proof.paths[0].terminal,
936            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path, 256))
937        );
938        assert_eq!(multi_proof.paths[0].depth, 2);
939        assert_eq!(multi_proof.siblings.len(), 2);
940        assert_eq!(multi_proof.siblings, vec![sibling1, sibling2]);
941    }
942
943    #[test]
944    pub fn test_multiproof_creation_two_path_proofs() {
945        let mut key_path_1 = [0; 32];
946        key_path_1[0] = 0b00000000;
947
948        let mut key_path_2 = [0; 32];
949        key_path_2[0] = 0b00111000;
950
951        let sibling1 = [1; 32];
952        let sibling2 = [2; 32];
953        let sibling3 = [3; 32];
954        let sibling4 = [4; 32];
955        let sibling5 = [5; 32];
956        let sibling6 = [6; 32];
957
958        let sibling_x = [b'x'; 32];
959
960        let path_proof_1 = PathProof {
961            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
962                key_path_1, 256,
963            )),
964            siblings: vec![sibling1, sibling2, sibling_x, sibling3, sibling4],
965        };
966        let path_proof_2 = PathProof {
967            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
968                key_path_2, 256,
969            )),
970            siblings: vec![sibling1, sibling2, sibling_x, sibling5, sibling6],
971        };
972
973        let multi_proof = MultiProof::from_path_proofs(vec![path_proof_1, path_proof_2]);
974
975        assert_eq!(multi_proof.paths.len(), 2);
976        assert_eq!(multi_proof.siblings.len(), 6);
977
978        assert_eq!(
979            multi_proof.paths[0].terminal,
980            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
981        );
982        assert_eq!(
983            multi_proof.paths[1].terminal,
984            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
985        );
986
987        assert_eq!(multi_proof.paths[0].depth, 5);
988        assert_eq!(multi_proof.paths[1].depth, 5);
989
990        assert_eq!(
991            multi_proof.siblings,
992            vec![sibling1, sibling2, sibling3, sibling4, sibling5, sibling6]
993        );
994    }
995
996    #[test]
997    pub fn test_multiproof_creation_two_path_proofs_256_depth() {
998        let mut key_path_1 = [0; 32];
999        key_path_1[31] = 0b00000000;
1000
1001        let mut key_path_2 = [0; 32];
1002        key_path_2[31] = 0b00000001;
1003
1004        let mut siblings_1: Vec<[u8; 32]> = (0..255).map(|i| [i; 32]).collect();
1005        let mut siblings_2 = siblings_1.clone();
1006        siblings_1.push([b'2'; 32]);
1007        siblings_2.push([b'1'; 32]);
1008
1009        let path_proof_1 = PathProof {
1010            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1011                key_path_1, 256,
1012            )),
1013            siblings: siblings_1.clone(),
1014        };
1015        let path_proof_2 = PathProof {
1016            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1017                key_path_2, 256,
1018            )),
1019            siblings: siblings_2,
1020        };
1021
1022        let multi_proof = MultiProof::from_path_proofs(vec![path_proof_1, path_proof_2]);
1023
1024        assert_eq!(multi_proof.paths.len(), 2);
1025        assert_eq!(multi_proof.siblings.len(), 255);
1026
1027        assert_eq!(
1028            multi_proof.paths[0].terminal,
1029            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
1030        );
1031        assert_eq!(
1032            multi_proof.paths[1].terminal,
1033            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
1034        );
1035
1036        assert_eq!(multi_proof.paths[0].depth, 256);
1037        assert_eq!(multi_proof.paths[1].depth, 256);
1038
1039        siblings_1.pop();
1040        assert_eq!(multi_proof.siblings, siblings_1);
1041    }
1042
1043    #[test]
1044    pub fn test_multiproof_creation_multiple_path_proofs() {
1045        let mut key_path_1 = [0; 32];
1046        key_path_1[0] = 0b00000000;
1047
1048        let mut key_path_2 = [0; 32];
1049        key_path_2[0] = 0b01000000;
1050
1051        let mut key_path_3 = [0; 32];
1052        key_path_3[0] = 0b01001100;
1053
1054        let mut key_path_4 = [0; 32];
1055        key_path_4[0] = 0b11101100;
1056
1057        let mut key_path_5 = [0; 32];
1058        key_path_5[0] = 0b11110100;
1059
1060        let mut key_path_6 = [0; 32];
1061        key_path_6[0] = 0b11111000;
1062
1063        let sibling1 = [1; 32];
1064        let sibling2 = [2; 32];
1065        let sibling3 = [3; 32];
1066        let sibling4 = [4; 32];
1067        let sibling5 = [5; 32];
1068        let sibling6 = [6; 32];
1069        let sibling7 = [7; 32];
1070        let sibling8 = [8; 32];
1071        let sibling9 = [9; 32];
1072        let sibling10 = [10; 32];
1073        let sibling11 = [11; 32];
1074        let sibling12 = [12; 32];
1075        let sibling13 = [13; 32];
1076        let sibling14 = [14; 32];
1077        let sibling15 = [15; 32];
1078        let sibling16 = [16; 32];
1079        let sibling17 = [17; 32];
1080        let sibling18 = [18; 32];
1081        let sibling19 = [19; 32];
1082
1083        let path_proof_1 = PathProof {
1084            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1085                key_path_1, 256,
1086            )),
1087            siblings: vec![sibling1, sibling2],
1088        };
1089
1090        let path_proof_2 = PathProof {
1091            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1092                key_path_2, 256,
1093            )),
1094            siblings: vec![sibling1, sibling3, sibling4, sibling5, sibling6, sibling7],
1095        };
1096
1097        let path_proof_3 = PathProof {
1098            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1099                key_path_3, 256,
1100            )),
1101            siblings: vec![sibling1, sibling3, sibling4, sibling5, sibling8, sibling9],
1102        };
1103
1104        let path_proof_4 = PathProof {
1105            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1106                key_path_4, 256,
1107            )),
1108            siblings: vec![
1109                sibling10, sibling11, sibling12, sibling13, sibling14, sibling15,
1110            ],
1111        };
1112
1113        let path_proof_5 = PathProof {
1114            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1115                key_path_5, 256,
1116            )),
1117            siblings: vec![
1118                sibling10, sibling11, sibling12, sibling16, sibling17, sibling18,
1119            ],
1120        };
1121
1122        let path_proof_6 = PathProof {
1123            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1124                key_path_6, 256,
1125            )),
1126            siblings: vec![sibling10, sibling11, sibling12, sibling16, sibling19],
1127        };
1128
1129        let multi_proof = MultiProof::from_path_proofs(vec![
1130            path_proof_1,
1131            path_proof_2,
1132            path_proof_3,
1133            path_proof_4,
1134            path_proof_5,
1135            path_proof_6,
1136        ]);
1137
1138        assert_eq!(multi_proof.paths.len(), 6);
1139        assert_eq!(multi_proof.siblings.len(), 9);
1140
1141        assert_eq!(
1142            multi_proof.paths[0].terminal,
1143            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
1144        );
1145        assert_eq!(
1146            multi_proof.paths[1].terminal,
1147            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
1148        );
1149        assert_eq!(
1150            multi_proof.paths[2].terminal,
1151            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_3, 256))
1152        );
1153        assert_eq!(
1154            multi_proof.paths[3].terminal,
1155            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_4, 256))
1156        );
1157        assert_eq!(
1158            multi_proof.paths[4].terminal,
1159            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_5, 256))
1160        );
1161        assert_eq!(
1162            multi_proof.paths[5].terminal,
1163            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_6, 256))
1164        );
1165
1166        assert_eq!(multi_proof.paths[0].depth, 2);
1167        assert_eq!(multi_proof.paths[1].depth, 6);
1168        assert_eq!(multi_proof.paths[2].depth, 6);
1169        assert_eq!(multi_proof.paths[3].depth, 6);
1170        assert_eq!(multi_proof.paths[4].depth, 6);
1171        assert_eq!(multi_proof.paths[5].depth, 5);
1172
1173        assert_eq!(
1174            multi_proof.siblings,
1175            vec![
1176                sibling4, sibling5, sibling7, sibling9, sibling11, sibling12, sibling14, sibling15,
1177                sibling18
1178            ]
1179        );
1180    }
1181
1182    #[test]
1183    pub fn test_multiproof_creation_ext_siblings_order() {
1184        let mut key_path_0 = [0; 32];
1185        key_path_0[0] = 0b00001000;
1186
1187        let mut key_path_1 = [0; 32];
1188        key_path_1[0] = 0b00010000;
1189
1190        let mut key_path_2 = [0; 32];
1191        key_path_2[0] = 0b10000000;
1192
1193        let mut key_path_3 = [0; 32];
1194        key_path_3[0] = 0b10000010;
1195
1196        let mut key_path_4 = [0; 32];
1197        key_path_4[0] = 0b10010001;
1198
1199        let mut key_path_5 = [0; 32];
1200        key_path_5[0] = 0b10010011;
1201
1202        let sibling1 = [1; 32];
1203        let sibling2 = [2; 32];
1204        let sibling3 = [3; 32];
1205        let sibling4 = [4; 32];
1206        let sibling5 = [5; 32];
1207        let sibling6 = [6; 32];
1208        let sibling7 = [7; 32];
1209        let sibling8 = [8; 32];
1210        let sibling9 = [9; 32];
1211        let sibling10 = [10; 32];
1212        let sibling11 = [11; 32];
1213        let sibling12 = [12; 32];
1214        let sibling13 = [13; 32];
1215        let sibling14 = [14; 32];
1216        let sibling15 = [15; 32];
1217        let sibling16 = [16; 32];
1218        let sibling17 = [17; 32];
1219        let sibling18 = [18; 32];
1220        let sibling19 = [19; 32];
1221        let sibling20 = [20; 32];
1222        let sibling21 = [21; 32];
1223        let sibling22 = [22; 32];
1224        let sibling23 = [23; 32];
1225        let sibling24 = [24; 32];
1226
1227        let path_proof_0 = PathProof {
1228            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1229                key_path_0, 256,
1230            )),
1231            siblings: vec![sibling1, sibling2, sibling3, sibling4, sibling5],
1232        };
1233
1234        let path_proof_1 = PathProof {
1235            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1236                key_path_1, 256,
1237            )),
1238            siblings: vec![sibling1, sibling2, sibling3, sibling6, sibling7],
1239        };
1240
1241        let path_proof_2 = PathProof {
1242            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1243                key_path_2, 256,
1244            )),
1245            siblings: vec![
1246                sibling8, sibling9, sibling10, sibling11, sibling12, sibling13, sibling14,
1247                sibling15,
1248            ],
1249        };
1250        let path_proof_3 = PathProof {
1251            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1252                key_path_3, 256,
1253            )),
1254            siblings: vec![
1255                sibling8, sibling9, sibling10, sibling11, sibling12, sibling13, sibling16,
1256                sibling17,
1257            ],
1258        };
1259
1260        let path_proof_4 = PathProof {
1261            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1262                key_path_4, 256,
1263            )),
1264            siblings: vec![
1265                sibling8, sibling9, sibling10, sibling18, sibling19, sibling20, sibling21,
1266                sibling22,
1267            ],
1268        };
1269
1270        let path_proof_5 = PathProof {
1271            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1272                key_path_5, 256,
1273            )),
1274            siblings: vec![
1275                sibling8, sibling9, sibling10, sibling18, sibling19, sibling20, sibling23,
1276                sibling24,
1277            ],
1278        };
1279
1280        let multi_proof = MultiProof::from_path_proofs(vec![
1281            path_proof_0,
1282            path_proof_1,
1283            path_proof_2,
1284            path_proof_3,
1285            path_proof_4,
1286            path_proof_5,
1287        ]);
1288
1289        assert_eq!(multi_proof.paths.len(), 6);
1290        assert_eq!(multi_proof.siblings.len(), 14);
1291
1292        assert_eq!(
1293            multi_proof.siblings,
1294            vec![
1295                sibling2, sibling3, sibling5, sibling7, sibling9, sibling10, sibling12, sibling13,
1296                sibling15, sibling17, sibling19, sibling20, sibling22, sibling24
1297            ]
1298        );
1299    }
1300
1301    #[test]
1302    fn multi_proof_failure_empty_witness() {
1303        let multi_proof = MultiProof::from_path_proofs(Vec::new());
1304
1305        let _verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
1306    }
1307
1308    #[test]
1309    fn multi_proof_verify_empty() {
1310        let multi_proof = MultiProof::from_path_proofs(Vec::new());
1311
1312        let verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
1313
1314        assert_eq!(
1315            verify_update::<Blake3Hasher>(&verified_multi_proof, Vec::new()).unwrap(),
1316            TERMINATOR,
1317        );
1318    }
1319
1320    #[test]
1321    fn multi_proof_verify_empty_with_provided_updates() {
1322        let multi_proof = MultiProof::from_path_proofs(Vec::new());
1323
1324        let verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
1325
1326        let mut key_path_0 = [0; 32];
1327        key_path_0[0] = 0b00001000;
1328
1329        let mut key_path_1 = [0; 32];
1330        key_path_1[0] = 0b00010000;
1331
1332        let mut key_path_2 = [0; 32];
1333        key_path_2[0] = 0b10000000;
1334
1335        let ops = vec![
1336            (key_path_0, Some([1; 32])),
1337            (key_path_1, Some([1; 32])),
1338            (key_path_2, Some([1; 32])),
1339        ];
1340
1341        let expected_root = build_trie::<Blake3Hasher>(
1342            0,
1343            ops.clone().into_iter().map(|(k, v)| (k, v.unwrap())),
1344            |_| {},
1345        );
1346
1347        assert_eq!(
1348            verify_update::<Blake3Hasher>(&verified_multi_proof, ops).unwrap(),
1349            expected_root,
1350        );
1351    }
1352
1353    #[test]
1354    pub fn test_verify_multiproof_two_leafs() {
1355        //     root
1356        //     /  \
1357        //    s3   v1
1358        //   / \
1359        //  v0  v2
1360
1361        let mut key_path_0 = [0; 32];
1362        key_path_0[0] = 0b00000000;
1363
1364        let mut key_path_1 = [0; 32];
1365        key_path_1[0] = 0b10000000;
1366
1367        let mut key_path_2 = [0; 32];
1368        key_path_2[0] = 0b01000000;
1369
1370        let leaf_0 = LeafData {
1371            key_path: key_path_0,
1372            value_hash: [0; 32],
1373        };
1374
1375        let leaf_1 = LeafData {
1376            key_path: key_path_1,
1377            value_hash: [1; 32],
1378        };
1379
1380        let leaf_2 = LeafData {
1381            key_path: key_path_2,
1382            value_hash: [2; 32],
1383        };
1384
1385        // this is the
1386        let v0 = Blake3Hasher::hash_leaf(&leaf_0);
1387        let v1 = Blake3Hasher::hash_leaf(&leaf_1);
1388        let v2 = Blake3Hasher::hash_leaf(&leaf_2);
1389        let s3 = Blake3Hasher::hash_internal(&InternalData {
1390            left: v0.clone(),
1391            right: v2,
1392        });
1393        let root = Blake3Hasher::hash_internal(&InternalData {
1394            left: s3,
1395            right: v1,
1396        });
1397
1398        let path_proof_0 = PathProof {
1399            terminal: PathProofTerminal::Leaf(leaf_0.clone()),
1400            siblings: vec![v1, v2],
1401        };
1402        let path_proof_1 = PathProof {
1403            terminal: PathProofTerminal::Leaf(leaf_1.clone()),
1404            siblings: vec![s3],
1405        };
1406
1407        let multi_proof =
1408            MultiProof::from_path_proofs(vec![path_proof_0.clone(), path_proof_1.clone()]);
1409
1410        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1411
1412        assert!(verified.confirm_value(&leaf_0).unwrap());
1413        assert!(verified.confirm_value(&leaf_1).unwrap());
1414    }
1415
1416    #[test]
1417    fn multi_proof_verify_2_leaves_with_provided_updates() {
1418        //     root
1419        //     /  \
1420        //    s3   v1
1421        //   / \
1422        //  v0  v2
1423
1424        let mut key_path_0 = [0; 32];
1425        key_path_0[0] = 0b00000000;
1426
1427        let mut key_path_1 = [0; 32];
1428        key_path_1[0] = 0b10000000;
1429
1430        let mut key_path_2 = [0; 32];
1431        key_path_2[0] = 0b01000000;
1432
1433        let leaf_0 = LeafData {
1434            key_path: key_path_0,
1435            value_hash: [0; 32],
1436        };
1437
1438        let leaf_1 = LeafData {
1439            key_path: key_path_1,
1440            value_hash: [1; 32],
1441        };
1442
1443        let leaf_2 = LeafData {
1444            key_path: key_path_2,
1445            value_hash: [2; 32],
1446        };
1447
1448        // this is the
1449        let v0 = Blake3Hasher::hash_leaf(&leaf_0);
1450        let v1 = Blake3Hasher::hash_leaf(&leaf_1);
1451        let v2 = Blake3Hasher::hash_leaf(&leaf_2);
1452        let s3 = Blake3Hasher::hash_internal(&InternalData {
1453            left: v0.clone(),
1454            right: v2,
1455        });
1456        let root = Blake3Hasher::hash_internal(&InternalData {
1457            left: s3,
1458            right: v1,
1459        });
1460
1461        let path_proof_0 = PathProof {
1462            terminal: PathProofTerminal::Leaf(leaf_0.clone()),
1463            siblings: vec![v1, v2],
1464        };
1465        let path_proof_1 = PathProof {
1466            terminal: PathProofTerminal::Leaf(leaf_1.clone()),
1467            siblings: vec![s3],
1468        };
1469
1470        let multi_proof =
1471            MultiProof::from_path_proofs(vec![path_proof_0.clone(), path_proof_1.clone()]);
1472
1473        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1474
1475        let mut key_path_3 = key_path_1;
1476        key_path_3[0] = 0b10100000;
1477
1478        let mut key_path_4 = key_path_0;
1479        key_path_4[0] = 0b00000100;
1480
1481        let ops = vec![
1482            (key_path_0, Some([2; 32])),
1483            (key_path_4, Some([1; 32])),
1484            (key_path_1, None),
1485            (key_path_3, Some([1; 32])),
1486        ];
1487
1488        let final_state = vec![
1489            (key_path_0, [2; 32]),
1490            (key_path_4, [1; 32]),
1491            (key_path_2, [2; 32]),
1492            (key_path_3, [1; 32]),
1493        ];
1494
1495        let expected_root = build_trie::<Blake3Hasher>(0, final_state, |_| {});
1496
1497        assert_eq!(
1498            verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
1499            expected_root,
1500        );
1501    }
1502
1503    #[test]
1504    fn verify_update_terminal_with_multi_unique_siblings() {
1505        // Regression test: exercises `CommonSiblings::extend` for a terminal
1506        // whose unique-sibling tail has length >= 2 with at least one
1507        // non-TERMINATOR entry. Earlier `verify_update` unit tests all had
1508        // terminal_n <= 1, masking the sibling-depth swap that affected
1509        // `verify_multi_proof_update`.
1510        //
1511        //                       root
1512        //                     /      \
1513        //                    i1       l_other
1514        //                   /  \
1515        //                  i2   T
1516        //                 /  \
1517        //                i3   T
1518        //               /  \
1519        //              i4   T
1520        //             /  \
1521        //            i5   T
1522        //           /  \
1523        //          i6   T
1524        //         /  \
1525        //        i7   T
1526        //       /  \
1527        //  l_alone  l_neighbor
1528
1529        let mut k_alone = [0u8; 32];
1530        k_alone[0] = 0b00000000;
1531        let mut k_neighbor = [0u8; 32];
1532        k_neighbor[0] = 0b00000001;
1533        let mut k_other = [0u8; 32];
1534        k_other[0] = 0b10000000;
1535
1536        let make_leaf = |key_path, value_byte| {
1537            let leaf_data = LeafData {
1538                key_path,
1539                value_hash: [value_byte; 32],
1540            };
1541            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1542            (leaf_data, hash)
1543        };
1544        let internal_hash =
1545            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1546
1547        let (l_alone, h_alone) = make_leaf(k_alone, 0xAA);
1548        let (l_neighbor, h_neighbor) = make_leaf(k_neighbor, 0xBB);
1549        let (l_other, h_other) = make_leaf(k_other, 0xCC);
1550
1551        let i7 = internal_hash(h_alone, h_neighbor);
1552        let i6 = internal_hash(i7, TERMINATOR);
1553        let i5 = internal_hash(i6, TERMINATOR);
1554        let i4 = internal_hash(i5, TERMINATOR);
1555        let i3 = internal_hash(i4, TERMINATOR);
1556        let i2 = internal_hash(i3, TERMINATOR);
1557        let i1 = internal_hash(i2, TERMINATOR);
1558        let root = internal_hash(i1, h_other);
1559
1560        // Witness for k_alone: 8 siblings at depths 1..=8 (ascending by depth).
1561        let path_proof_alone = PathProof {
1562            terminal: PathProofTerminal::Leaf(l_alone.clone()),
1563            siblings: vec![
1564                h_other, TERMINATOR, TERMINATOR, TERMINATOR, TERMINATOR, TERMINATOR, TERMINATOR,
1565                h_neighbor,
1566            ],
1567        };
1568        let path_proof_other = PathProof {
1569            terminal: PathProofTerminal::Leaf(l_other.clone()),
1570            siblings: vec![i1],
1571        };
1572
1573        let multi_proof = MultiProof::from_path_proofs(vec![path_proof_alone, path_proof_other]);
1574
1575        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1576
1577        // Update k_alone with a new value.
1578        let new_value: ValueHash = [0xDD; 32];
1579        let ops = vec![(k_alone, Some(new_value))];
1580
1581        // Expected post-update root: rebuild the trie with k_alone's new value.
1582        let new_state = vec![
1583            (k_alone, new_value),
1584            (k_neighbor, l_neighbor.value_hash),
1585            (k_other, l_other.value_hash),
1586        ];
1587        let expected_root = build_trie::<Blake3Hasher>(0, new_state, |_| {});
1588
1589        assert_eq!(
1590            verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
1591            expected_root,
1592        );
1593    }
1594
1595    #[test]
1596    fn multi_proof_verify_4_leaves_with_long_bisections() {
1597        //              R
1598        //              i1
1599        //              i2
1600        //              i3
1601        //              i4
1602        //           i5a    i5a
1603        //           i6a    i6b
1604        //           i7a    i7b
1605        //         l8a l8b l8c l8d
1606
1607        let make_leaf = |key_path, value_byte| {
1608            let leaf_data = LeafData {
1609                key_path,
1610                value_hash: [value_byte; 32],
1611            };
1612
1613            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1614            (leaf_data, hash)
1615        };
1616        let internal_hash =
1617            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1618
1619        let mut key_path_0 = [0; 32];
1620        key_path_0[0] = 0b00000000;
1621
1622        let mut key_path_1 = [0; 32];
1623        key_path_1[0] = 0b00000001;
1624
1625        let mut key_path_2 = [0; 32];
1626        key_path_2[0] = 0b00001000;
1627
1628        let mut key_path_3 = [0; 32];
1629        key_path_3[0] = 0b00001001;
1630
1631        let (leaf_a, l8a) = make_leaf(key_path_0, 1);
1632        let (leaf_b, l8b) = make_leaf(key_path_1, 1);
1633        let (leaf_c, l8c) = make_leaf(key_path_2, 1);
1634        let (leaf_d, l8d) = make_leaf(key_path_3, 1);
1635
1636        let i7a = internal_hash(l8a, l8b);
1637        let i7b = internal_hash(l8c, l8d);
1638
1639        let i6a = internal_hash(i7a, [7; 32]);
1640        let i6b = internal_hash(i7b, [7; 32]);
1641
1642        let i5a = internal_hash(i6a, [6; 32]);
1643        let i5b = internal_hash(i6b, [6; 32]);
1644
1645        let i4 = internal_hash(i5a, i5b);
1646        let i3 = internal_hash(i4, [4; 32]);
1647        let i2 = internal_hash(i3, [3; 32]);
1648        let i1 = internal_hash(i2, [2; 32]);
1649        let root = internal_hash(i1, [1; 32]);
1650
1651        let path_proof_a = PathProof {
1652            terminal: PathProofTerminal::Leaf(leaf_a.clone()),
1653            siblings: vec![
1654                [1; 32], [2; 32], [3; 32], [4; 32], i5b, [6; 32], [7; 32], l8b,
1655            ],
1656        };
1657        let path_proof_b = PathProof {
1658            terminal: PathProofTerminal::Leaf(leaf_b.clone()),
1659            siblings: vec![
1660                [1; 32], [2; 32], [3; 32], [4; 32], i5b, [6; 32], [7; 32], l8a,
1661            ],
1662        };
1663        let path_proof_c = PathProof {
1664            terminal: PathProofTerminal::Leaf(leaf_c.clone()),
1665            siblings: vec![
1666                [1; 32], [2; 32], [3; 32], [4; 32], i5a, [6; 32], [7; 32], l8d,
1667            ],
1668        };
1669        let path_proof_d = PathProof {
1670            terminal: PathProofTerminal::Leaf(leaf_d.clone()),
1671            siblings: vec![
1672                [1; 32], [2; 32], [3; 32], [4; 32], i5a, [6; 32], [7; 32], l8c,
1673            ],
1674        };
1675
1676        let multi_proof = MultiProof::from_path_proofs(vec![
1677            path_proof_a.clone(),
1678            path_proof_b.clone(),
1679            path_proof_c.clone(),
1680            path_proof_d.clone(),
1681        ]);
1682
1683        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1684
1685        let ops = vec![(key_path_0, Some([69; 32])), (key_path_3, Some([69; 32]))];
1686
1687        let (_, l8a) = make_leaf(key_path_0, 69);
1688        let (_, l8b) = make_leaf(key_path_1, 1);
1689        let (_, l8c) = make_leaf(key_path_2, 1);
1690        let (_, l8d) = make_leaf(key_path_3, 69);
1691
1692        let i7a = internal_hash(l8a, l8b);
1693        let i7b = internal_hash(l8c, l8d);
1694
1695        let i6a = internal_hash(i7a, [7; 32]);
1696        let i6b = internal_hash(i7b, [7; 32]);
1697
1698        let i5a = internal_hash(i6a, [6; 32]);
1699        let i5b = internal_hash(i6b, [6; 32]);
1700
1701        let i4 = internal_hash(i5a, i5b);
1702
1703        let i3 = internal_hash(i4, [4; 32]);
1704        let i2 = internal_hash(i3, [3; 32]);
1705        let i1 = internal_hash(i2, [2; 32]);
1706        let post_root = internal_hash(i1, [1; 32]);
1707
1708        assert_eq!(
1709            verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
1710            post_root,
1711        );
1712    }
1713
1714    #[test]
1715    pub fn test_verify_multiproof_multiple_leafs() {
1716        //                       root
1717        //                 /            \
1718        //                i3            i6
1719        //             /     \       /      \
1720        //            i2      T     v3      i5
1721        //          /     \                /   \
1722        //         i1     v2              i4   v5
1723        //        / \                    /  \
1724        //       v0  v1                 v4   T
1725
1726        let path = |byte| [byte; 32];
1727
1728        let k0 = path(0b00000000);
1729        let k1 = path(0b00011000);
1730        let k2 = path(0b00101101);
1731        let k3 = path(0b10101010);
1732        let k4 = path(0b11000011);
1733        let k5 = path(0b11100010);
1734
1735        let make_leaf = |key_path| {
1736            let leaf_data = LeafData {
1737                key_path,
1738                value_hash: [key_path[0]; 32],
1739            };
1740
1741            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1742            (leaf_data, hash)
1743        };
1744        let internal_hash =
1745            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1746
1747        let (l0, v0) = make_leaf(k0);
1748        let (l1, v1) = make_leaf(k1);
1749        let (l2, v2) = make_leaf(k2);
1750        let (l3, v3) = make_leaf(k3);
1751        let (l4, v4) = make_leaf(k4);
1752        let (l5, v5) = make_leaf(k5);
1753
1754        let i1 = internal_hash(v0, v1);
1755        let i2 = internal_hash(i1, v2);
1756        let i3 = internal_hash(i2, TERMINATOR);
1757
1758        let i4 = internal_hash(v4, TERMINATOR);
1759        let i5 = internal_hash(i4, v5);
1760        let i6 = internal_hash(v3, i5);
1761
1762        let root = internal_hash(i3, i6);
1763
1764        let leaf_proof = |leaf, siblings| PathProof {
1765            terminal: PathProofTerminal::Leaf(leaf),
1766            siblings,
1767        };
1768
1769        let path_proof_0 = leaf_proof(l0.clone(), vec![i6, TERMINATOR, v2, v1]);
1770        let path_proof_1 = leaf_proof(l1.clone(), vec![i6, TERMINATOR, v2, v0]);
1771        let path_proof_2 = leaf_proof(l2.clone(), vec![i6, TERMINATOR, i1]);
1772        let path_proof_3 = leaf_proof(l3.clone(), vec![i3, i5]);
1773        let path_proof_4 = leaf_proof(l4.clone(), vec![i3, v3, v5, TERMINATOR]);
1774        let path_proof_5 = leaf_proof(l5.clone(), vec![i3, v3, i4]);
1775
1776        let multi_proof = MultiProof::from_path_proofs(vec![
1777            path_proof_0.clone(),
1778            path_proof_1.clone(),
1779            path_proof_2.clone(),
1780            path_proof_3.clone(),
1781            path_proof_4.clone(),
1782            path_proof_5.clone(),
1783        ]);
1784
1785        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1786        assert!(verified.confirm_value(&l0).unwrap());
1787        assert!(verified.confirm_value(&l1).unwrap());
1788        assert!(verified.confirm_value(&l2).unwrap());
1789        assert!(verified.confirm_value(&l3).unwrap());
1790        assert!(verified.confirm_value(&l4).unwrap());
1791        assert!(verified.confirm_value(&l5).unwrap());
1792    }
1793
1794    #[test]
1795    pub fn test_verify_multiproof_siblings_structure() {
1796        //                           root
1797        //                     /            \
1798        //                    v0           i10
1799        //                               /     \
1800        //                              i9     e7
1801        //                            /     \
1802        //                           i8     e6
1803        //                       /        \
1804        //                      i4        i7
1805        //                     /  \      /  \
1806        //                    i3   e3   e5   i6
1807        //                   /  \           /  \
1808        //                  i2   e2        e4   i5
1809        //                 /  \               /  \
1810        //                i1   e1            v3   v4
1811        //               /  \
1812        //              v1  v2
1813
1814        let path = |byte| [byte; 32];
1815
1816        let k0 = path(0b00000000);
1817        let k1 = path(0b10000000);
1818        let k2 = path(0b10000001);
1819        let k3 = path(0b10011100);
1820        let k4 = path(0b10011110);
1821
1822        let make_leaf = |key_path| {
1823            let leaf_data = LeafData {
1824                key_path,
1825                value_hash: [key_path[0]; 32],
1826            };
1827
1828            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1829            (leaf_data, hash)
1830        };
1831        let internal_hash =
1832            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1833
1834        let (_l0, v0) = make_leaf(k0);
1835        let (l1, v1) = make_leaf(k1);
1836        let (l2, v2) = make_leaf(k2);
1837        let (l3, v3) = make_leaf(k3);
1838        let (l4, v4) = make_leaf(k4);
1839
1840        let e1 = [1; 32];
1841        let e2 = [2; 32];
1842        let e3 = [3; 32];
1843        let e4 = [4; 32];
1844        let e5 = [5; 32];
1845        let e6 = [6; 32];
1846        let e7 = TERMINATOR;
1847
1848        let i1 = internal_hash(v1, v2);
1849        let i2 = internal_hash(i1, e1);
1850        let i3 = internal_hash(i2, e2);
1851        let i4 = internal_hash(i3, e3);
1852
1853        let i5 = internal_hash(v3, v4);
1854        let i6 = internal_hash(e4, i5);
1855        let i7 = internal_hash(e5, i6);
1856
1857        let i8 = internal_hash(i4, i7);
1858        let i9 = internal_hash(i8, e6);
1859        let i10 = internal_hash(i9, e7);
1860
1861        let root = internal_hash(v0, i10);
1862
1863        let leaf_proof = |leaf, siblings| PathProof {
1864            terminal: PathProofTerminal::Leaf(leaf),
1865            siblings,
1866        };
1867
1868        let path_proof_1 = leaf_proof(l1.clone(), vec![v0, e7, e6, i7, e3, e2, e1, v2]);
1869        let path_proof_2 = leaf_proof(l2.clone(), vec![v0, e7, e6, i7, e3, e2, e1, v1]);
1870        let path_proof_3 = leaf_proof(l3.clone(), vec![v0, e7, e6, i4, e5, e4, v4]);
1871        let path_proof_4 = leaf_proof(l4.clone(), vec![v0, e7, e6, i4, e5, e4, v3]);
1872
1873        let multi_proof = MultiProof::from_path_proofs(vec![
1874            path_proof_1.clone(),
1875            path_proof_2.clone(),
1876            path_proof_3.clone(),
1877            path_proof_4.clone(),
1878        ]);
1879
1880        assert_eq!(multi_proof.siblings, vec![v0, e7, e6, e3, e2, e1, e5, e4]);
1881
1882        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1883        assert!(verified.confirm_value(&l1).unwrap());
1884        assert!(verified.confirm_value(&l2).unwrap());
1885        assert!(verified.confirm_value(&l3).unwrap());
1886        assert!(verified.confirm_value(&l4).unwrap());
1887    }
1888
1889    #[test]
1890
1891    fn test_verify_update_underflow_prefix_paths() {
1892        // 1. Define paths with prefix relationship
1893        let bits_prefix = bitvec![u8, Msb0; 1, 0, 1, 0]; // length 4
1894        let bits_longer = bitvec![u8, Msb0; 1, 0, 1, 0, 1, 1]; // length 6 (prefix + 2 bits)
1895        let kp_prefix = key_with_prefix(bits_prefix.iter().by_vals());
1896        let kp_longer = key_with_prefix(bits_longer.iter().by_vals());
1897
1898        // 2. Create corresponding LeafData and Nodes
1899        let leaf_prefix = LeafData {
1900            key_path: kp_prefix,
1901            value_hash: [1; 32],
1902        };
1903
1904        let leaf_longer = LeafData {
1905            key_path: kp_longer,
1906            value_hash: [2; 32],
1907        };
1908
1909        let node_prefix = Blake3Hasher::hash_leaf(&leaf_prefix);
1910        let node_longer = Blake3Hasher::hash_leaf(&leaf_longer);
1911
1912        // 3. Construct the VerifiedMultiProof
1913        let vmp_prefix = VerifiedMultiPath {
1914            terminal: PathProofTerminal::Leaf(leaf_prefix.clone()),
1915            depth: bits_prefix.len(),
1916            unique_siblings: 0..0, // Minimal example
1917        };
1918
1919        let vmp_longer = VerifiedMultiPath {
1920            terminal: PathProofTerminal::Leaf(leaf_longer.clone()),
1921            depth: bits_longer.len(),
1922            unique_siblings: 0..0, // Minimal example
1923        };
1924
1925        // Create a plausible root for the test setup.
1926        // For the purpose of triggering the bug, the exact root structure isn't critical,
1927        // as long as the VerifiedMultiProof structure is valid and contains the prefix paths.
1928        let plausible_root = Blake3Hasher::hash_internal(&InternalData {
1929            left: node_prefix,
1930            right: node_longer,
1931        });
1932
1933        let verified_proof = VerifiedMultiProof {
1934            inner: vec![vmp_prefix, vmp_longer],
1935
1936            bisections: Vec::new(), // Minimal example
1937
1938            siblings: Vec::new(), // Minimal example
1939
1940            root: plausible_root,
1941        };
1942
1943        // 4. Create operations falling under each path
1944        let mut key_op1_bits = bits_prefix.clone();
1945
1946        key_op1_bits.push(false); // e.g., 10100 (falls under 1010)
1947
1948        let key_op1 = key_with_prefix(key_op1_bits.iter().by_vals());
1949
1950        let mut key_op2_bits = bits_longer.clone();
1951
1952        key_op2_bits.push(true); // e.g., 1010111 (falls under 101011)
1953
1954        let key_op2 = key_with_prefix(key_op2_bits.iter().by_vals());
1955
1956        let ops = vec![
1957            (key_op1, Some(ValueHash::default())), // Op under prefix path
1958            (key_op2, Some(ValueHash::default())), // Op under longer path
1959        ];
1960
1961        // Ensure ops are sorted (should be by construction here)
1962        assert!(ops[0].0 < ops[1].0);
1963
1964        // This should trigger the error.
1965        match verify_update::<Blake3Hasher>(&verified_proof, ops).unwrap_err() {
1966            MultiVerifyUpdateError::PathPrefixOfAnother => (),
1967            _ => panic!(),
1968        }
1969    }
1970}