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)]
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)]
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                false,
635            );
636            self.bisection_stack.push(next_bisection.clone());
637        }
638
639        let terminal_n = next_terminal.unique_siblings.end - next_terminal.unique_siblings.start;
640        self.extend(
641            next_terminal.depth - terminal_n + 1,
642            next_terminal.unique_siblings.end,
643            &proof.siblings,
644            true,
645        );
646        self.terminal_index += 1;
647    }
648
649    fn pop_to(&mut self, depth: usize) {
650        while self
651            .bisection_stack
652            .last()
653            .map_or(false, |b| b.start_depth >= depth)
654        {
655            let _ = self.bisection_stack.pop();
656        }
657
658        while self.stack.last().map_or(false, |(d, _)| *d >= depth) {
659            let _ = self.stack.pop();
660        }
661    }
662
663    fn extend(&mut self, start_depth: usize, end: usize, siblings: &[Node], reverse: bool) {
664        if reverse {
665            for (i, sibling) in siblings[self.taken_siblings..end].iter().rev().enumerate() {
666                self.stack.push((start_depth + i, *sibling))
667            }
668        } else {
669            for (i, sibling) in siblings[self.taken_siblings..end].iter().enumerate() {
670                self.stack.push((start_depth + i, *sibling))
671            }
672        }
673
674        self.taken_siblings = end;
675    }
676
677    fn pop_if_at_depth(&mut self, depth: usize) -> Option<Node> {
678        if self.stack.last().map_or(false, |(d, _)| *d == depth) {
679            self.stack.pop().map(|(_, n)| n)
680        } else {
681            None
682        }
683    }
684}
685
686/// Verify an update operation against a verified multi-proof. This follows a similar algorithm to
687/// the multi-item update, but without altering any backing storage.
688///
689/// `ops` should contain all updates to be processed. It should be sorted (ascending) by keypath,
690/// without duplicates.
691///
692/// All provided operations should have a key-path which is in scope for the multi proof.
693///
694/// Returns the root of the trie obtained after application of the given updates in the `paths`
695/// vector. In case the `paths` is empty, `prev_root` is returned.
696pub fn verify_update<H: NodeHasher>(
697    proof: &VerifiedMultiProof,
698    ops: Vec<(KeyPath, Option<ValueHash>)>,
699) -> Result<Node, MultiVerifyUpdateError> {
700    if ops.is_empty() {
701        return Ok(proof.root);
702    }
703
704    // left frontier
705    let mut pending_siblings: Vec<(Node, usize)> = Vec::new();
706
707    let mut last_key = None;
708    let mut last_terminal_index = None;
709    let mut next_pending_terminal_index = None;
710
711    let mut working_ops = Vec::new();
712
713    let mut common_siblings = CommonSiblings::new();
714    let ops_len = ops.len();
715
716    // chain with dummy item for handling the last batch.
717    for (i, (key, op)) in ops.into_iter().chain(Some(([0u8; 32], None))).enumerate() {
718        let is_last = i == ops_len;
719
720        if is_last {
721            let updated_terminal_index = last_terminal_index.unwrap_or(0);
722            let start = next_pending_terminal_index.unwrap_or(0);
723
724            // ingest all terminals from the next one needing an update to the end.
725            for terminal_index in start..proof.inner.len() {
726                let next = if terminal_index == proof.inner.len() - 1 {
727                    None
728                } else {
729                    Some(terminal_index + 1)
730                };
731
732                let terminal = &proof.inner[terminal_index];
733                let next_terminal = next.map(|n| &proof.inner[n]);
734
735                let ops = if terminal_index == updated_terminal_index {
736                    &working_ops[..]
737                } else {
738                    &[]
739                };
740
741                common_siblings.advance(&proof);
742                hash_and_compact_terminal::<H>(
743                    &mut pending_siblings,
744                    terminal,
745                    next_terminal,
746                    &mut common_siblings,
747                    ops,
748                )?;
749            }
750        } else {
751            // enforce key ordering.
752            if let Some(last_key) = last_key {
753                if key <= last_key {
754                    return Err(MultiVerifyUpdateError::OpsOutOfOrder);
755                }
756            }
757            last_key = Some(key);
758
759            // find terminal index for the operation, erroring if out of scope.
760            let mut next_terminal_index = last_terminal_index.unwrap_or(0);
761            if proof.inner.len() <= next_terminal_index {
762                return Err(MultiVerifyUpdateError::OpOutOfScope);
763            }
764
765            while !terminal_contains(&proof.inner[next_terminal_index], &key) {
766                next_terminal_index += 1;
767                if proof.inner.len() <= next_terminal_index {
768                    return Err(MultiVerifyUpdateError::OpOutOfScope);
769                }
770            }
771
772            // if this is either the first op or this has the same terminal as the previous op...
773            if last_terminal_index.map_or(true, |x| x == next_terminal_index) {
774                last_terminal_index = Some(next_terminal_index);
775                working_ops.push((key, op));
776                continue;
777            }
778
779            // UNWRAP: guaranteed by above.
780            let updated_index = last_terminal_index.unwrap();
781            last_terminal_index = Some(next_terminal_index);
782
783            // ingest all terminals up to current.
784            let start = next_pending_terminal_index.unwrap_or(0);
785
786            for terminal_index in start..updated_index {
787                let terminal = &proof.inner[terminal_index];
788                let next_terminal = Some(&proof.inner[terminal_index + 1]);
789
790                common_siblings.advance(&proof);
791                hash_and_compact_terminal::<H>(
792                    &mut pending_siblings,
793                    terminal,
794                    next_terminal,
795                    &mut common_siblings,
796                    &[],
797                )?;
798            }
799
800            // ingest the currently updated terminal.
801            let ops = core::mem::replace(&mut working_ops, Vec::new());
802            working_ops.push((key, op));
803
804            let terminal = &proof.inner[updated_index];
805            let next_terminal = proof.inner.get(updated_index + 1);
806            common_siblings.advance(&proof);
807
808            hash_and_compact_terminal::<H>(
809                &mut pending_siblings,
810                terminal,
811                next_terminal,
812                &mut common_siblings,
813                &ops,
814            )?;
815
816            next_pending_terminal_index = Some(updated_index + 1);
817        };
818    }
819
820    // UNWRAP: This is always full unless the update is empty
821    Ok(pending_siblings.pop().map(|n| n.0).unwrap_or(proof.root))
822}
823
824fn hash_and_compact_terminal<H: NodeHasher>(
825    pending_siblings: &mut Vec<(Node, usize)>,
826    terminal: &VerifiedMultiPath,
827    next_terminal: Option<&VerifiedMultiPath>,
828    common_siblings: &mut CommonSiblings,
829    ops: &[(KeyPath, Option<ValueHash>)],
830) -> Result<(), MultiVerifyUpdateError> {
831    let leaf = terminal.terminal.as_leaf_option();
832    let skip = terminal.depth;
833
834    let up_layers = if let Some(next_terminal) = next_terminal {
835        let n = shared_bits(terminal.terminal.path(), next_terminal.terminal.path());
836
837        // SANITY: this is impossible in a well-formed input but we catch it as an error.
838        // The reason this is impossible is because no terminal should be a prefix of another
839        // terminal (by definition)
840        if n == skip {
841            return Err(MultiVerifyUpdateError::PathPrefixOfAnother);
842        }
843
844        // n always < skip
845        // we want to end at layer n + 1
846        skip - (n + 1)
847    } else {
848        skip // go to root
849    };
850
851    let ops = crate::update::leaf_ops_spliced(leaf, &ops);
852    let sub_root = crate::update::build_trie::<H>(skip, ops, |_| {});
853
854    let mut cur_node = sub_root;
855    let mut cur_layer = skip;
856    let end_layer = skip - up_layers;
857
858    // iterate siblings up to the point of collision with next path, replacing with pending
859    // siblings, and compacting where possible.
860    // push (node, end_layer) to pending siblings when done.
861    for bit in terminal.terminal.path()[..terminal.depth]
862        .iter()
863        .by_vals()
864        .rev()
865        .take(up_layers)
866    {
867        let sibling = if pending_siblings.last().map_or(false, |p| p.1 == cur_layer) {
868            // is this even possible? maybe not. but being extra cautious...
869            let _ = common_siblings.pop_if_at_depth(cur_layer);
870            // UNWRAP: guaranteed to exist.
871            pending_siblings.pop().unwrap().0
872        } else {
873            // UNWRAP: `common_siblings` holds everything which isn't computed dynamically from branch
874            // to branch. basically, it's the inverse of `pending_siblings`. so if the sibling isn't
875            // in pending_siblings, it's in here.
876            common_siblings.pop_if_at_depth(cur_layer).unwrap()
877        };
878
879        match (NodeKind::of::<H>(&cur_node), NodeKind::of::<H>(&sibling)) {
880            (NodeKind::Terminator, NodeKind::Terminator) => {}
881            (NodeKind::Leaf, NodeKind::Terminator) => {}
882            (NodeKind::Terminator, NodeKind::Leaf) => {
883                // relocate sibling upwards.
884                cur_node = sibling;
885            }
886            _ => {
887                // otherwise, internal
888                let node_data = if bit {
889                    InternalData {
890                        left: sibling,
891                        right: cur_node,
892                    }
893                } else {
894                    InternalData {
895                        left: cur_node,
896                        right: sibling,
897                    }
898                };
899                cur_node = H::hash_internal(&node_data);
900            }
901        }
902
903        cur_layer -= 1;
904    }
905
906    pending_siblings.push((cur_node, end_layer));
907    Ok(())
908}
909
910#[cfg(test)]
911mod tests {
912    use super::{verify, verify_update, MultiProof};
913
914    use crate::proof::multi_proof::{
915        MultiVerifyUpdateError, VerifiedMultiPath, VerifiedMultiProof,
916    };
917    use crate::{
918        hasher::{Blake3Hasher, NodeHasher},
919        proof::{PathProof, PathProofTerminal},
920        trie::{InternalData, KeyPath, LeafData, ValueHash, TERMINATOR},
921        trie_pos::TriePosition,
922        update::build_trie,
923    };
924    use bitvec::prelude::*;
925
926    #[test]
927    pub fn test_multiproof_creation_single_path_proof() {
928        let mut key_path = [0; 32];
929        key_path[0] = 0b10000000;
930        let sibling1 = [1; 32];
931        let sibling2 = [2; 32];
932        let path_proof = PathProof {
933            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
934                key_path, 256,
935            )),
936            siblings: vec![sibling1, sibling2],
937        };
938
939        let multi_proof = MultiProof::from_path_proofs(vec![path_proof]);
940        assert_eq!(multi_proof.paths.len(), 1);
941        assert_eq!(
942            multi_proof.paths[0].terminal,
943            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path, 256))
944        );
945        assert_eq!(multi_proof.paths[0].depth, 2);
946        assert_eq!(multi_proof.siblings.len(), 2);
947        assert_eq!(multi_proof.siblings, vec![sibling1, sibling2]);
948    }
949
950    #[test]
951    pub fn test_multiproof_creation_two_path_proofs() {
952        let mut key_path_1 = [0; 32];
953        key_path_1[0] = 0b00000000;
954
955        let mut key_path_2 = [0; 32];
956        key_path_2[0] = 0b00111000;
957
958        let sibling1 = [1; 32];
959        let sibling2 = [2; 32];
960        let sibling3 = [3; 32];
961        let sibling4 = [4; 32];
962        let sibling5 = [5; 32];
963        let sibling6 = [6; 32];
964
965        let sibling_x = [b'x'; 32];
966
967        let path_proof_1 = PathProof {
968            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
969                key_path_1, 256,
970            )),
971            siblings: vec![sibling1, sibling2, sibling_x, sibling3, sibling4],
972        };
973        let path_proof_2 = PathProof {
974            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
975                key_path_2, 256,
976            )),
977            siblings: vec![sibling1, sibling2, sibling_x, sibling5, sibling6],
978        };
979
980        let multi_proof = MultiProof::from_path_proofs(vec![path_proof_1, path_proof_2]);
981
982        assert_eq!(multi_proof.paths.len(), 2);
983        assert_eq!(multi_proof.siblings.len(), 6);
984
985        assert_eq!(
986            multi_proof.paths[0].terminal,
987            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
988        );
989        assert_eq!(
990            multi_proof.paths[1].terminal,
991            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
992        );
993
994        assert_eq!(multi_proof.paths[0].depth, 5);
995        assert_eq!(multi_proof.paths[1].depth, 5);
996
997        assert_eq!(
998            multi_proof.siblings,
999            vec![sibling1, sibling2, sibling3, sibling4, sibling5, sibling6]
1000        );
1001    }
1002
1003    #[test]
1004    pub fn test_multiproof_creation_two_path_proofs_256_depth() {
1005        let mut key_path_1 = [0; 32];
1006        key_path_1[31] = 0b00000000;
1007
1008        let mut key_path_2 = [0; 32];
1009        key_path_2[31] = 0b00000001;
1010
1011        let mut siblings_1: Vec<[u8; 32]> = (0..255).map(|i| [i; 32]).collect();
1012        let mut siblings_2 = siblings_1.clone();
1013        siblings_1.push([b'2'; 32]);
1014        siblings_2.push([b'1'; 32]);
1015
1016        let path_proof_1 = PathProof {
1017            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1018                key_path_1, 256,
1019            )),
1020            siblings: siblings_1.clone(),
1021        };
1022        let path_proof_2 = PathProof {
1023            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1024                key_path_2, 256,
1025            )),
1026            siblings: siblings_2,
1027        };
1028
1029        let multi_proof = MultiProof::from_path_proofs(vec![path_proof_1, path_proof_2]);
1030
1031        assert_eq!(multi_proof.paths.len(), 2);
1032        assert_eq!(multi_proof.siblings.len(), 255);
1033
1034        assert_eq!(
1035            multi_proof.paths[0].terminal,
1036            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
1037        );
1038        assert_eq!(
1039            multi_proof.paths[1].terminal,
1040            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
1041        );
1042
1043        assert_eq!(multi_proof.paths[0].depth, 256);
1044        assert_eq!(multi_proof.paths[1].depth, 256);
1045
1046        siblings_1.pop();
1047        assert_eq!(multi_proof.siblings, siblings_1);
1048    }
1049
1050    #[test]
1051    pub fn test_multiproof_creation_multiple_path_proofs() {
1052        let mut key_path_1 = [0; 32];
1053        key_path_1[0] = 0b00000000;
1054
1055        let mut key_path_2 = [0; 32];
1056        key_path_2[0] = 0b01000000;
1057
1058        let mut key_path_3 = [0; 32];
1059        key_path_3[0] = 0b01001100;
1060
1061        let mut key_path_4 = [0; 32];
1062        key_path_4[0] = 0b11101100;
1063
1064        let mut key_path_5 = [0; 32];
1065        key_path_5[0] = 0b11110100;
1066
1067        let mut key_path_6 = [0; 32];
1068        key_path_6[0] = 0b11111000;
1069
1070        let sibling1 = [1; 32];
1071        let sibling2 = [2; 32];
1072        let sibling3 = [3; 32];
1073        let sibling4 = [4; 32];
1074        let sibling5 = [5; 32];
1075        let sibling6 = [6; 32];
1076        let sibling7 = [7; 32];
1077        let sibling8 = [8; 32];
1078        let sibling9 = [9; 32];
1079        let sibling10 = [10; 32];
1080        let sibling11 = [11; 32];
1081        let sibling12 = [12; 32];
1082        let sibling13 = [13; 32];
1083        let sibling14 = [14; 32];
1084        let sibling15 = [15; 32];
1085        let sibling16 = [16; 32];
1086        let sibling17 = [17; 32];
1087        let sibling18 = [18; 32];
1088        let sibling19 = [19; 32];
1089
1090        let path_proof_1 = PathProof {
1091            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1092                key_path_1, 256,
1093            )),
1094            siblings: vec![sibling1, sibling2],
1095        };
1096
1097        let path_proof_2 = PathProof {
1098            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1099                key_path_2, 256,
1100            )),
1101            siblings: vec![sibling1, sibling3, sibling4, sibling5, sibling6, sibling7],
1102        };
1103
1104        let path_proof_3 = PathProof {
1105            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1106                key_path_3, 256,
1107            )),
1108            siblings: vec![sibling1, sibling3, sibling4, sibling5, sibling8, sibling9],
1109        };
1110
1111        let path_proof_4 = PathProof {
1112            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1113                key_path_4, 256,
1114            )),
1115            siblings: vec![
1116                sibling10, sibling11, sibling12, sibling13, sibling14, sibling15,
1117            ],
1118        };
1119
1120        let path_proof_5 = PathProof {
1121            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1122                key_path_5, 256,
1123            )),
1124            siblings: vec![
1125                sibling10, sibling11, sibling12, sibling16, sibling17, sibling18,
1126            ],
1127        };
1128
1129        let path_proof_6 = PathProof {
1130            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1131                key_path_6, 256,
1132            )),
1133            siblings: vec![sibling10, sibling11, sibling12, sibling16, sibling19],
1134        };
1135
1136        let multi_proof = MultiProof::from_path_proofs(vec![
1137            path_proof_1,
1138            path_proof_2,
1139            path_proof_3,
1140            path_proof_4,
1141            path_proof_5,
1142            path_proof_6,
1143        ]);
1144
1145        assert_eq!(multi_proof.paths.len(), 6);
1146        assert_eq!(multi_proof.siblings.len(), 9);
1147
1148        assert_eq!(
1149            multi_proof.paths[0].terminal,
1150            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
1151        );
1152        assert_eq!(
1153            multi_proof.paths[1].terminal,
1154            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
1155        );
1156        assert_eq!(
1157            multi_proof.paths[2].terminal,
1158            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_3, 256))
1159        );
1160        assert_eq!(
1161            multi_proof.paths[3].terminal,
1162            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_4, 256))
1163        );
1164        assert_eq!(
1165            multi_proof.paths[4].terminal,
1166            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_5, 256))
1167        );
1168        assert_eq!(
1169            multi_proof.paths[5].terminal,
1170            PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_6, 256))
1171        );
1172
1173        assert_eq!(multi_proof.paths[0].depth, 2);
1174        assert_eq!(multi_proof.paths[1].depth, 6);
1175        assert_eq!(multi_proof.paths[2].depth, 6);
1176        assert_eq!(multi_proof.paths[3].depth, 6);
1177        assert_eq!(multi_proof.paths[4].depth, 6);
1178        assert_eq!(multi_proof.paths[5].depth, 5);
1179
1180        assert_eq!(
1181            multi_proof.siblings,
1182            vec![
1183                sibling4, sibling5, sibling7, sibling9, sibling11, sibling12, sibling14, sibling15,
1184                sibling18
1185            ]
1186        );
1187    }
1188
1189    #[test]
1190    pub fn test_multiproof_creation_ext_siblings_order() {
1191        let mut key_path_0 = [0; 32];
1192        key_path_0[0] = 0b00001000;
1193
1194        let mut key_path_1 = [0; 32];
1195        key_path_1[0] = 0b00010000;
1196
1197        let mut key_path_2 = [0; 32];
1198        key_path_2[0] = 0b10000000;
1199
1200        let mut key_path_3 = [0; 32];
1201        key_path_3[0] = 0b10000010;
1202
1203        let mut key_path_4 = [0; 32];
1204        key_path_4[0] = 0b10010001;
1205
1206        let mut key_path_5 = [0; 32];
1207        key_path_5[0] = 0b10010011;
1208
1209        let sibling1 = [1; 32];
1210        let sibling2 = [2; 32];
1211        let sibling3 = [3; 32];
1212        let sibling4 = [4; 32];
1213        let sibling5 = [5; 32];
1214        let sibling6 = [6; 32];
1215        let sibling7 = [7; 32];
1216        let sibling8 = [8; 32];
1217        let sibling9 = [9; 32];
1218        let sibling10 = [10; 32];
1219        let sibling11 = [11; 32];
1220        let sibling12 = [12; 32];
1221        let sibling13 = [13; 32];
1222        let sibling14 = [14; 32];
1223        let sibling15 = [15; 32];
1224        let sibling16 = [16; 32];
1225        let sibling17 = [17; 32];
1226        let sibling18 = [18; 32];
1227        let sibling19 = [19; 32];
1228        let sibling20 = [20; 32];
1229        let sibling21 = [21; 32];
1230        let sibling22 = [22; 32];
1231        let sibling23 = [23; 32];
1232        let sibling24 = [24; 32];
1233
1234        let path_proof_0 = PathProof {
1235            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1236                key_path_0, 256,
1237            )),
1238            siblings: vec![sibling1, sibling2, sibling3, sibling4, sibling5],
1239        };
1240
1241        let path_proof_1 = PathProof {
1242            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1243                key_path_1, 256,
1244            )),
1245            siblings: vec![sibling1, sibling2, sibling3, sibling6, sibling7],
1246        };
1247
1248        let path_proof_2 = PathProof {
1249            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1250                key_path_2, 256,
1251            )),
1252            siblings: vec![
1253                sibling8, sibling9, sibling10, sibling11, sibling12, sibling13, sibling14,
1254                sibling15,
1255            ],
1256        };
1257        let path_proof_3 = PathProof {
1258            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1259                key_path_3, 256,
1260            )),
1261            siblings: vec![
1262                sibling8, sibling9, sibling10, sibling11, sibling12, sibling13, sibling16,
1263                sibling17,
1264            ],
1265        };
1266
1267        let path_proof_4 = PathProof {
1268            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1269                key_path_4, 256,
1270            )),
1271            siblings: vec![
1272                sibling8, sibling9, sibling10, sibling18, sibling19, sibling20, sibling21,
1273                sibling22,
1274            ],
1275        };
1276
1277        let path_proof_5 = PathProof {
1278            terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
1279                key_path_5, 256,
1280            )),
1281            siblings: vec![
1282                sibling8, sibling9, sibling10, sibling18, sibling19, sibling20, sibling23,
1283                sibling24,
1284            ],
1285        };
1286
1287        let multi_proof = MultiProof::from_path_proofs(vec![
1288            path_proof_0,
1289            path_proof_1,
1290            path_proof_2,
1291            path_proof_3,
1292            path_proof_4,
1293            path_proof_5,
1294        ]);
1295
1296        assert_eq!(multi_proof.paths.len(), 6);
1297        assert_eq!(multi_proof.siblings.len(), 14);
1298
1299        assert_eq!(
1300            multi_proof.siblings,
1301            vec![
1302                sibling2, sibling3, sibling5, sibling7, sibling9, sibling10, sibling12, sibling13,
1303                sibling15, sibling17, sibling19, sibling20, sibling22, sibling24
1304            ]
1305        );
1306    }
1307
1308    #[test]
1309    fn multi_proof_failure_empty_witness() {
1310        let multi_proof = MultiProof::from_path_proofs(Vec::new());
1311
1312        let _verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
1313    }
1314
1315    #[test]
1316    fn multi_proof_verify_empty() {
1317        let multi_proof = MultiProof::from_path_proofs(Vec::new());
1318
1319        let verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
1320
1321        assert_eq!(
1322            verify_update::<Blake3Hasher>(&verified_multi_proof, Vec::new()).unwrap(),
1323            TERMINATOR,
1324        );
1325    }
1326
1327    #[test]
1328    fn multi_proof_verify_empty_with_provided_updates() {
1329        let multi_proof = MultiProof::from_path_proofs(Vec::new());
1330
1331        let verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
1332
1333        let mut key_path_0 = [0; 32];
1334        key_path_0[0] = 0b00001000;
1335
1336        let mut key_path_1 = [0; 32];
1337        key_path_1[0] = 0b00010000;
1338
1339        let mut key_path_2 = [0; 32];
1340        key_path_2[0] = 0b10000000;
1341
1342        let ops = vec![
1343            (key_path_0, Some([1; 32])),
1344            (key_path_1, Some([1; 32])),
1345            (key_path_2, Some([1; 32])),
1346        ];
1347
1348        let expected_root = build_trie::<Blake3Hasher>(
1349            0,
1350            ops.clone().into_iter().map(|(k, v)| (k, v.unwrap())),
1351            |_| {},
1352        );
1353
1354        assert_eq!(
1355            verify_update::<Blake3Hasher>(&verified_multi_proof, ops).unwrap(),
1356            expected_root,
1357        );
1358    }
1359
1360    #[test]
1361    pub fn test_verify_multiproof_two_leafs() {
1362        //     root
1363        //     /  \
1364        //    s3   v1
1365        //   / \
1366        //  v0  v2
1367
1368        let mut key_path_0 = [0; 32];
1369        key_path_0[0] = 0b00000000;
1370
1371        let mut key_path_1 = [0; 32];
1372        key_path_1[0] = 0b10000000;
1373
1374        let mut key_path_2 = [0; 32];
1375        key_path_2[0] = 0b01000000;
1376
1377        let leaf_0 = LeafData {
1378            key_path: key_path_0,
1379            value_hash: [0; 32],
1380        };
1381
1382        let leaf_1 = LeafData {
1383            key_path: key_path_1,
1384            value_hash: [1; 32],
1385        };
1386
1387        let leaf_2 = LeafData {
1388            key_path: key_path_2,
1389            value_hash: [2; 32],
1390        };
1391
1392        // this is the
1393        let v0 = Blake3Hasher::hash_leaf(&leaf_0);
1394        let v1 = Blake3Hasher::hash_leaf(&leaf_1);
1395        let v2 = Blake3Hasher::hash_leaf(&leaf_2);
1396        let s3 = Blake3Hasher::hash_internal(&InternalData {
1397            left: v0.clone(),
1398            right: v2,
1399        });
1400        let root = Blake3Hasher::hash_internal(&InternalData {
1401            left: s3,
1402            right: v1,
1403        });
1404
1405        let path_proof_0 = PathProof {
1406            terminal: PathProofTerminal::Leaf(leaf_0.clone()),
1407            siblings: vec![v1, v2],
1408        };
1409        let path_proof_1 = PathProof {
1410            terminal: PathProofTerminal::Leaf(leaf_1.clone()),
1411            siblings: vec![s3],
1412        };
1413
1414        let multi_proof =
1415            MultiProof::from_path_proofs(vec![path_proof_0.clone(), path_proof_1.clone()]);
1416
1417        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1418
1419        assert!(verified.confirm_value(&leaf_0).unwrap());
1420        assert!(verified.confirm_value(&leaf_1).unwrap());
1421    }
1422
1423    #[test]
1424    fn multi_proof_verify_2_leaves_with_provided_updates() {
1425        //     root
1426        //     /  \
1427        //    s3   v1
1428        //   / \
1429        //  v0  v2
1430
1431        let mut key_path_0 = [0; 32];
1432        key_path_0[0] = 0b00000000;
1433
1434        let mut key_path_1 = [0; 32];
1435        key_path_1[0] = 0b10000000;
1436
1437        let mut key_path_2 = [0; 32];
1438        key_path_2[0] = 0b01000000;
1439
1440        let leaf_0 = LeafData {
1441            key_path: key_path_0,
1442            value_hash: [0; 32],
1443        };
1444
1445        let leaf_1 = LeafData {
1446            key_path: key_path_1,
1447            value_hash: [1; 32],
1448        };
1449
1450        let leaf_2 = LeafData {
1451            key_path: key_path_2,
1452            value_hash: [2; 32],
1453        };
1454
1455        // this is the
1456        let v0 = Blake3Hasher::hash_leaf(&leaf_0);
1457        let v1 = Blake3Hasher::hash_leaf(&leaf_1);
1458        let v2 = Blake3Hasher::hash_leaf(&leaf_2);
1459        let s3 = Blake3Hasher::hash_internal(&InternalData {
1460            left: v0.clone(),
1461            right: v2,
1462        });
1463        let root = Blake3Hasher::hash_internal(&InternalData {
1464            left: s3,
1465            right: v1,
1466        });
1467
1468        let path_proof_0 = PathProof {
1469            terminal: PathProofTerminal::Leaf(leaf_0.clone()),
1470            siblings: vec![v1, v2],
1471        };
1472        let path_proof_1 = PathProof {
1473            terminal: PathProofTerminal::Leaf(leaf_1.clone()),
1474            siblings: vec![s3],
1475        };
1476
1477        let multi_proof =
1478            MultiProof::from_path_proofs(vec![path_proof_0.clone(), path_proof_1.clone()]);
1479
1480        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1481
1482        let mut key_path_3 = key_path_1;
1483        key_path_3[0] = 0b10100000;
1484
1485        let mut key_path_4 = key_path_0;
1486        key_path_4[0] = 0b00000100;
1487
1488        let ops = vec![
1489            (key_path_0, Some([2; 32])),
1490            (key_path_4, Some([1; 32])),
1491            (key_path_1, None),
1492            (key_path_3, Some([1; 32])),
1493        ];
1494
1495        let final_state = vec![
1496            (key_path_0, [2; 32]),
1497            (key_path_4, [1; 32]),
1498            (key_path_2, [2; 32]),
1499            (key_path_3, [1; 32]),
1500        ];
1501
1502        let expected_root = build_trie::<Blake3Hasher>(0, final_state, |_| {});
1503
1504        assert_eq!(
1505            verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
1506            expected_root,
1507        );
1508    }
1509
1510    #[test]
1511    fn multi_proof_verify_4_leaves_with_long_bisections() {
1512        //              R
1513        //              i1
1514        //              i2
1515        //              i3
1516        //              i4
1517        //           i5a    i5a
1518        //           i6a    i6b
1519        //           i7a    i7b
1520        //         l8a l8b l8c l8d
1521
1522        let make_leaf = |key_path, value_byte| {
1523            let leaf_data = LeafData {
1524                key_path,
1525                value_hash: [value_byte; 32],
1526            };
1527
1528            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1529            (leaf_data, hash)
1530        };
1531        let internal_hash =
1532            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1533
1534        let mut key_path_0 = [0; 32];
1535        key_path_0[0] = 0b00000000;
1536
1537        let mut key_path_1 = [0; 32];
1538        key_path_1[0] = 0b00000001;
1539
1540        let mut key_path_2 = [0; 32];
1541        key_path_2[0] = 0b00001000;
1542
1543        let mut key_path_3 = [0; 32];
1544        key_path_3[0] = 0b00001001;
1545
1546        let (leaf_a, l8a) = make_leaf(key_path_0, 1);
1547        let (leaf_b, l8b) = make_leaf(key_path_1, 1);
1548        let (leaf_c, l8c) = make_leaf(key_path_2, 1);
1549        let (leaf_d, l8d) = make_leaf(key_path_3, 1);
1550
1551        let i7a = internal_hash(l8a, l8b);
1552        let i7b = internal_hash(l8c, l8d);
1553
1554        let i6a = internal_hash(i7a, [7; 32]);
1555        let i6b = internal_hash(i7b, [7; 32]);
1556
1557        let i5a = internal_hash(i6a, [6; 32]);
1558        let i5b = internal_hash(i6b, [6; 32]);
1559
1560        let i4 = internal_hash(i5a, i5b);
1561        let i3 = internal_hash(i4, [4; 32]);
1562        let i2 = internal_hash(i3, [3; 32]);
1563        let i1 = internal_hash(i2, [2; 32]);
1564        let root = internal_hash(i1, [1; 32]);
1565
1566        let path_proof_a = PathProof {
1567            terminal: PathProofTerminal::Leaf(leaf_a.clone()),
1568            siblings: vec![
1569                [1; 32], [2; 32], [3; 32], [4; 32], i5b, [6; 32], [7; 32], l8b,
1570            ],
1571        };
1572        let path_proof_b = PathProof {
1573            terminal: PathProofTerminal::Leaf(leaf_b.clone()),
1574            siblings: vec![
1575                [1; 32], [2; 32], [3; 32], [4; 32], i5b, [6; 32], [7; 32], l8a,
1576            ],
1577        };
1578        let path_proof_c = PathProof {
1579            terminal: PathProofTerminal::Leaf(leaf_c.clone()),
1580            siblings: vec![
1581                [1; 32], [2; 32], [3; 32], [4; 32], i5a, [6; 32], [7; 32], l8d,
1582            ],
1583        };
1584        let path_proof_d = PathProof {
1585            terminal: PathProofTerminal::Leaf(leaf_d.clone()),
1586            siblings: vec![
1587                [1; 32], [2; 32], [3; 32], [4; 32], i5a, [6; 32], [7; 32], l8c,
1588            ],
1589        };
1590
1591        let multi_proof = MultiProof::from_path_proofs(vec![
1592            path_proof_a.clone(),
1593            path_proof_b.clone(),
1594            path_proof_c.clone(),
1595            path_proof_d.clone(),
1596        ]);
1597
1598        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1599
1600        let ops = vec![(key_path_0, Some([69; 32])), (key_path_3, Some([69; 32]))];
1601
1602        let (_, l8a) = make_leaf(key_path_0, 69);
1603        let (_, l8b) = make_leaf(key_path_1, 1);
1604        let (_, l8c) = make_leaf(key_path_2, 1);
1605        let (_, l8d) = make_leaf(key_path_3, 69);
1606
1607        let i7a = internal_hash(l8a, l8b);
1608        let i7b = internal_hash(l8c, l8d);
1609
1610        let i6a = internal_hash(i7a, [7; 32]);
1611        let i6b = internal_hash(i7b, [7; 32]);
1612
1613        let i5a = internal_hash(i6a, [6; 32]);
1614        let i5b = internal_hash(i6b, [6; 32]);
1615
1616        let i4 = internal_hash(i5a, i5b);
1617
1618        let i3 = internal_hash(i4, [4; 32]);
1619        let i2 = internal_hash(i3, [3; 32]);
1620        let i1 = internal_hash(i2, [2; 32]);
1621        let post_root = internal_hash(i1, [1; 32]);
1622
1623        assert_eq!(
1624            verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
1625            post_root,
1626        );
1627    }
1628
1629    #[test]
1630    pub fn test_verify_multiproof_multiple_leafs() {
1631        //                       root
1632        //                 /            \
1633        //                i3            i6
1634        //             /     \       /      \
1635        //            i2      T     v3      i5
1636        //          /     \                /   \
1637        //         i1     v2              i4   v5
1638        //        / \                    /  \
1639        //       v0  v1                 v4   T
1640
1641        let path = |byte| [byte; 32];
1642
1643        let k0 = path(0b00000000);
1644        let k1 = path(0b00011000);
1645        let k2 = path(0b00101101);
1646        let k3 = path(0b10101010);
1647        let k4 = path(0b11000011);
1648        let k5 = path(0b11100010);
1649
1650        let make_leaf = |key_path| {
1651            let leaf_data = LeafData {
1652                key_path,
1653                value_hash: [key_path[0]; 32],
1654            };
1655
1656            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1657            (leaf_data, hash)
1658        };
1659        let internal_hash =
1660            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1661
1662        let (l0, v0) = make_leaf(k0);
1663        let (l1, v1) = make_leaf(k1);
1664        let (l2, v2) = make_leaf(k2);
1665        let (l3, v3) = make_leaf(k3);
1666        let (l4, v4) = make_leaf(k4);
1667        let (l5, v5) = make_leaf(k5);
1668
1669        let i1 = internal_hash(v0, v1);
1670        let i2 = internal_hash(i1, v2);
1671        let i3 = internal_hash(i2, TERMINATOR);
1672
1673        let i4 = internal_hash(v4, TERMINATOR);
1674        let i5 = internal_hash(i4, v5);
1675        let i6 = internal_hash(v3, i5);
1676
1677        let root = internal_hash(i3, i6);
1678
1679        let leaf_proof = |leaf, siblings| PathProof {
1680            terminal: PathProofTerminal::Leaf(leaf),
1681            siblings,
1682        };
1683
1684        let path_proof_0 = leaf_proof(l0.clone(), vec![i6, TERMINATOR, v2, v1]);
1685        let path_proof_1 = leaf_proof(l1.clone(), vec![i6, TERMINATOR, v2, v0]);
1686        let path_proof_2 = leaf_proof(l2.clone(), vec![i6, TERMINATOR, i1]);
1687        let path_proof_3 = leaf_proof(l3.clone(), vec![i3, i5]);
1688        let path_proof_4 = leaf_proof(l4.clone(), vec![i3, v3, v5, TERMINATOR]);
1689        let path_proof_5 = leaf_proof(l5.clone(), vec![i3, v3, i4]);
1690
1691        let multi_proof = MultiProof::from_path_proofs(vec![
1692            path_proof_0.clone(),
1693            path_proof_1.clone(),
1694            path_proof_2.clone(),
1695            path_proof_3.clone(),
1696            path_proof_4.clone(),
1697            path_proof_5.clone(),
1698        ]);
1699
1700        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1701        assert!(verified.confirm_value(&l0).unwrap());
1702        assert!(verified.confirm_value(&l1).unwrap());
1703        assert!(verified.confirm_value(&l2).unwrap());
1704        assert!(verified.confirm_value(&l3).unwrap());
1705        assert!(verified.confirm_value(&l4).unwrap());
1706        assert!(verified.confirm_value(&l5).unwrap());
1707    }
1708
1709    #[test]
1710    pub fn test_verify_multiproof_siblings_structure() {
1711        //                           root
1712        //                     /            \
1713        //                    v0           i10
1714        //                               /     \
1715        //                              i9     e7
1716        //                            /     \
1717        //                           i8     e6
1718        //                       /        \
1719        //                      i4        i7
1720        //                     /  \      /  \
1721        //                    i3   e3   e5   i6
1722        //                   /  \           /  \
1723        //                  i2   e2        e4   i5
1724        //                 /  \               /  \
1725        //                i1   e1            v3   v4
1726        //               /  \
1727        //              v1  v2
1728
1729        let path = |byte| [byte; 32];
1730
1731        let k0 = path(0b00000000);
1732        let k1 = path(0b10000000);
1733        let k2 = path(0b10000001);
1734        let k3 = path(0b10011100);
1735        let k4 = path(0b10011110);
1736
1737        let make_leaf = |key_path| {
1738            let leaf_data = LeafData {
1739                key_path,
1740                value_hash: [key_path[0]; 32],
1741            };
1742
1743            let hash = Blake3Hasher::hash_leaf(&leaf_data);
1744            (leaf_data, hash)
1745        };
1746        let internal_hash =
1747            |left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
1748
1749        let (_l0, v0) = make_leaf(k0);
1750        let (l1, v1) = make_leaf(k1);
1751        let (l2, v2) = make_leaf(k2);
1752        let (l3, v3) = make_leaf(k3);
1753        let (l4, v4) = make_leaf(k4);
1754
1755        let e1 = [1; 32];
1756        let e2 = [2; 32];
1757        let e3 = [3; 32];
1758        let e4 = [4; 32];
1759        let e5 = [5; 32];
1760        let e6 = [6; 32];
1761        let e7 = TERMINATOR;
1762
1763        let i1 = internal_hash(v1, v2);
1764        let i2 = internal_hash(i1, e1);
1765        let i3 = internal_hash(i2, e2);
1766        let i4 = internal_hash(i3, e3);
1767
1768        let i5 = internal_hash(v3, v4);
1769        let i6 = internal_hash(e4, i5);
1770        let i7 = internal_hash(e5, i6);
1771
1772        let i8 = internal_hash(i4, i7);
1773        let i9 = internal_hash(i8, e6);
1774        let i10 = internal_hash(i9, e7);
1775
1776        let root = internal_hash(v0, i10);
1777
1778        let leaf_proof = |leaf, siblings| PathProof {
1779            terminal: PathProofTerminal::Leaf(leaf),
1780            siblings,
1781        };
1782
1783        let path_proof_1 = leaf_proof(l1.clone(), vec![v0, e7, e6, i7, e3, e2, e1, v2]);
1784        let path_proof_2 = leaf_proof(l2.clone(), vec![v0, e7, e6, i7, e3, e2, e1, v1]);
1785        let path_proof_3 = leaf_proof(l3.clone(), vec![v0, e7, e6, i4, e5, e4, v4]);
1786        let path_proof_4 = leaf_proof(l4.clone(), vec![v0, e7, e6, i4, e5, e4, v3]);
1787
1788        let multi_proof = MultiProof::from_path_proofs(vec![
1789            path_proof_1.clone(),
1790            path_proof_2.clone(),
1791            path_proof_3.clone(),
1792            path_proof_4.clone(),
1793        ]);
1794
1795        assert_eq!(multi_proof.siblings, vec![v0, e7, e6, e3, e2, e1, e5, e4]);
1796
1797        let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
1798        assert!(verified.confirm_value(&l1).unwrap());
1799        assert!(verified.confirm_value(&l2).unwrap());
1800        assert!(verified.confirm_value(&l3).unwrap());
1801        assert!(verified.confirm_value(&l4).unwrap());
1802    }
1803
1804    #[test]
1805
1806    fn test_verify_update_underflow_prefix_paths() {
1807        // 1. Define paths with prefix relationship
1808        let bits_prefix = bitvec![u8, Msb0; 1, 0, 1, 0]; // length 4
1809        let bits_longer = bitvec![u8, Msb0; 1, 0, 1, 0, 1, 1]; // length 6 (prefix + 2 bits)
1810
1811        // Helper to create KeyPath from BitVec (simplified, assumes short paths)
1812        let keypath_from_bits = |bits: &BitSlice<u8, Msb0>| -> KeyPath {
1813            let mut kp = KeyPath::default();
1814
1815            for (i, bit) in bits.iter().by_vals().enumerate() {
1816                if i >= 256 {
1817                    break;
1818                }
1819
1820                if bit {
1821                    kp[i / 8] |= 1 << (7 - (i % 8));
1822                }
1823            }
1824
1825            kp
1826        };
1827
1828        let kp_prefix = keypath_from_bits(&bits_prefix);
1829        let kp_longer = keypath_from_bits(&bits_longer);
1830
1831        // 2. Create corresponding LeafData and Nodes
1832        let leaf_prefix = LeafData {
1833            key_path: kp_prefix,
1834            value_hash: [1; 32],
1835        };
1836
1837        let leaf_longer = LeafData {
1838            key_path: kp_longer,
1839            value_hash: [2; 32],
1840        };
1841
1842        let node_prefix = Blake3Hasher::hash_leaf(&leaf_prefix);
1843        let node_longer = Blake3Hasher::hash_leaf(&leaf_longer);
1844
1845        // 3. Construct the VerifiedMultiProof
1846        let vmp_prefix = VerifiedMultiPath {
1847            terminal: PathProofTerminal::Leaf(leaf_prefix.clone()),
1848            depth: bits_prefix.len(),
1849            unique_siblings: 0..0, // Minimal example
1850        };
1851
1852        let vmp_longer = VerifiedMultiPath {
1853            terminal: PathProofTerminal::Leaf(leaf_longer.clone()),
1854            depth: bits_longer.len(),
1855            unique_siblings: 0..0, // Minimal example
1856        };
1857
1858        // Create a plausible root for the test setup.
1859        // For the purpose of triggering the bug, the exact root structure isn't critical,
1860        // as long as the VerifiedMultiProof structure is valid and contains the prefix paths.
1861        let plausible_root = Blake3Hasher::hash_internal(&InternalData {
1862            left: node_prefix,
1863            right: node_longer,
1864        });
1865
1866        let verified_proof = VerifiedMultiProof {
1867            inner: vec![vmp_prefix, vmp_longer],
1868
1869            bisections: Vec::new(), // Minimal example
1870
1871            siblings: Vec::new(), // Minimal example
1872
1873            root: plausible_root,
1874        };
1875
1876        // 4. Create operations falling under each path
1877        let mut key_op1_bits = bits_prefix.clone();
1878
1879        key_op1_bits.push(false); // e.g., 10100 (falls under 1010)
1880
1881        let key_op1 = keypath_from_bits(&key_op1_bits);
1882
1883        let mut key_op2_bits = bits_longer.clone();
1884
1885        key_op2_bits.push(true); // e.g., 1010111 (falls under 101011)
1886
1887        let key_op2 = keypath_from_bits(&key_op2_bits);
1888
1889        let ops = vec![
1890            (key_op1, Some(ValueHash::default())), // Op under prefix path
1891            (key_op2, Some(ValueHash::default())), // Op under longer path
1892        ];
1893
1894        // Ensure ops are sorted (should be by construction here)
1895        assert!(ops[0].0 < ops[1].0);
1896
1897        // This should trigger the error.
1898        match verify_update::<Blake3Hasher>(&verified_proof, ops).unwrap_err() {
1899            MultiVerifyUpdateError::PathPrefixOfAnother => (),
1900            _ => panic!(),
1901        }
1902    }
1903}