openzeppelin_crypto/
merkle.rs

1//! This module deals with verification of Merkle Tree proofs.
2//!
3//! The tree and the proofs can be generated using `OpenZeppelin`'s
4//! [merkle tree library](https://github.com/OpenZeppelin/merkle-tree). You will
5//! find a quickstart guide in its README.
6//!
7//! WARNING: You should avoid using leaf values that are 64 bytes long
8//! prior to hashing, or use a hash function other than keccak256 for
9//! hashing leaves. This is because the concatenation of a sorted pair
10//! of internal nodes in the Merkle tree could be reinterpreted as a
11//! leaf value. `OpenZeppelin`'s JavaScript library generates Merkle trees
12//! that are safe against this attack out of the box.
13use alloc::vec::Vec;
14use core::marker::PhantomData;
15
16use crate::{
17    hash::{commutative_hash_pair, BuildHasher, Hasher},
18    KeccakBuilder,
19};
20
21type Bytes32 = [u8; 32];
22
23/// Verify merkle proofs.
24pub struct Verifier<B = KeccakBuilder>(PhantomData<B>)
25where
26    B: BuildHasher;
27
28impl Verifier<KeccakBuilder> {
29    /// Verify that `leaf` is part of a Merkle tree defined by `root` by using
30    /// `proof` and the default `keccak256` hashing algorithm.
31    ///
32    /// A new root is rebuilt by traversing up the Merkle tree. The `proof`
33    /// provided must contain sibling hashes on the branch starting from the
34    /// leaf to the root of the tree. Each pair of leaves and each pair of
35    /// pre-images are assumed to be sorted.
36    ///
37    /// A `proof` is valid if and only if the rebuilt hash matches the root
38    /// of the tree.
39    ///
40    /// # Arguments
41    ///
42    /// * `proof` - A slice of hashes that constitute the merkle proof.
43    /// * `root` - The root of the merkle tree, in bytes.
44    /// * `leaf` - The leaf of the merkle tree to proof, in bytes.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// use openzeppelin_crypto::merkle::Verifier;
50    /// use hex_literal::hex;
51    ///
52    /// let root  = hex!("0000000000000000000000000000000000000000000000000000000000000000");
53    /// let leaf  = hex!("0000000000000000000000000000000000000000000000000000000000000000");
54    /// let proof = hex!("0000000000000000000000000000000000000000000000000000000000000000");
55    ///
56    /// let verification = Verifier::verify(&[proof], root, leaf);
57    /// assert!(!verification);
58    /// ```
59    #[must_use]
60    pub fn verify(proof: &[Bytes32], root: Bytes32, leaf: Bytes32) -> bool {
61        Verifier::verify_with_builder(proof, root, leaf, &KeccakBuilder)
62    }
63
64    /// Verify multiple `leaves` can be simultaneously proven to be a part of
65    /// a Merkle tree defined by `root` by using a `proof` with `proof_flags`
66    /// and a `hasher`.
67    ///
68    /// The `proof` must contain the sibling hashes one would need to rebuild
69    /// the root starting from `leaves`. `proof_flags` represents whether a
70    /// hash must be computed using a `proof` member. A new root is rebuilt by
71    /// starting from the `leaves` and traversing up the Merkle tree.
72    ///
73    /// The procedure incrementally reconstructs all inner nodes by combining
74    /// a leaf/inner node with either another leaf/inner node or a `proof`
75    /// sibling node, depending on each proof flag being true or false
76    /// respectively, i.e., the `i`-th hash must be computed using the proof if
77    /// `proof_flags[i] == false`.
78    ///
79    /// CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs,
80    /// it is sufficient to ensure that:
81    /// - The tree is complete (but not necessarily perfect).
82    /// - The leaves to be proven are in the opposite order they appear in the
83    ///   tree (i.e., as seen from right to left starting at the deepest layer
84    ///   and continuing at the next layer).
85    ///
86    /// NOTE: This implementation is *not* equivalent to it's Solidity
87    /// counterpart. In Rust, access to uninitialized memory panics, which
88    /// means we don't need to check that the whole proof array has been
89    /// processed. Both implementations will revert for the same inputs, but
90    /// for different reasons. See <https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p>
91    ///
92    /// # Arguments
93    ///
94    /// * `proof` - A slice of hashes that constitute the merkle proof.
95    /// * `proof_flags` - A slice of booleans that determine whether to hash
96    ///   leaves or the proof.
97    /// * `root` - The root of the merkle tree, in bytes.
98    /// * `leaves` - A slice of hashes that constitute the leaves of the merkle
99    ///   tree to be proven, each leaf in bytes.
100    ///
101    /// # Errors
102    ///
103    /// * [`MultiProofError`] - If the arguments are well-formed, but invalid.
104    ///
105    /// # Panics
106    ///
107    /// * If the proof is malicious (with an out-of-bounds error). See <https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p>
108    ///
109    /// # Examples
110    ///
111    /// ```rust
112    /// use openzeppelin_crypto::merkle::Verifier;
113    /// use hex_literal::hex;
114    ///
115    /// let root   =  hex!("6deb52b5da8fd108f79fab00341f38d2587896634c646ee52e49f845680a70c8");
116    /// let leaves = [hex!("19ba6c6333e0e9a15bf67523e0676e2f23eb8e574092552d5e888c64a4bb3681"),
117    ///               hex!("c62a8cfa41edc0ef6f6ae27a2985b7d39c7fea770787d7e104696c6e81f64848"),
118    ///               hex!("eba909cf4bb90c6922771d7f126ad0fd11dfde93f3937a196274e1ac20fd2f5b")];
119    /// let proof  = [hex!("9a4f64e953595df82d1b4f570d34c4f4f0cfaf729a61e9d60e83e579e1aa283e"),
120    ///               hex!("8076923e76cf01a7c048400a2304c9a9c23bbbdac3a98ea3946340fdafbba34f")];
121    ///
122    /// let proof_flags = [false, true, false, true];
123    ///
124    /// let verification =
125    ///     Verifier::verify_multi_proof(&proof, &proof_flags, root, &leaves);
126    /// assert!(verification.unwrap());
127    /// ```
128    pub fn verify_multi_proof(
129        proof: &[Bytes32],
130        proof_flags: &[bool],
131        root: Bytes32,
132        leaves: &[Bytes32],
133    ) -> Result<bool, MultiProofError> {
134        Verifier::verify_multi_proof_with_builder(
135            proof,
136            proof_flags,
137            root,
138            leaves,
139            &KeccakBuilder,
140        )
141    }
142}
143
144impl<B> Verifier<B>
145where
146    B: BuildHasher,
147    B::Hasher: Hasher<Output = Bytes32>,
148{
149    /// Verify that `leaf` is part of a Merkle tree defined by `root` by using
150    /// `proof` and a custom hashing algorithm defined by `builder`. See
151    /// [`BuildHasher`] for more information on how to construct a builder.
152    ///
153    /// Merkle tree hashing process must be constructed commutatively when using
154    /// custom hashing algorithms.
155    ///
156    /// WARNING: This is a lower-level function. For most use cases,
157    /// [`Verifier::verify`], which uses `keccak256` as a hashing algorithm,
158    /// should be enough. Using other hashing algorithm may have unexpected
159    /// results.
160    ///
161    /// # Arguments
162    ///
163    /// * `proof` - A slice of hashes that constitute the merkle proof.
164    /// * `root` - The root of the merkle tree, in bytes.
165    /// * `leaf` - The leaf of the merkle tree to proof, in bytes.
166    /// * `builder` - A [`BuildHasher`] that represents a hashing algorithm.
167    ///
168    /// # Examples
169    ///
170    /// ```
171    /// use openzeppelin_crypto::{merkle::Verifier, KeccakBuilder};
172    /// use hex_literal::hex;
173    ///
174    /// let root  = hex!("0000000000000000000000000000000000000000000000000000000000000000");
175    /// let leaf  = hex!("0000000000000000000000000000000000000000000000000000000000000000");
176    /// let proof = hex!("0000000000000000000000000000000000000000000000000000000000000000");
177    ///
178    /// let verification = Verifier::verify_with_builder(&[proof], root, leaf, &KeccakBuilder);
179    /// assert!(!verification);
180    /// ```
181    pub fn verify_with_builder(
182        proof: &[Bytes32],
183        root: Bytes32,
184        mut leaf: Bytes32,
185        builder: &B,
186    ) -> bool {
187        for &hash in proof {
188            leaf = commutative_hash_pair(&leaf, &hash, builder.build_hasher());
189        }
190
191        leaf == root
192    }
193
194    /// Verify multiple `leaves` can be simultaneously proven to be a part of
195    /// a Merkle tree defined by `root` by using a `proof` with `proof_flags`
196    /// and a custom hashing algorithm defined by `builder`. See
197    /// [`BuildHasher`] for more information on how to construct a builder.
198    ///
199    /// Merkle tree hashing process must be constructed commutatively when using
200    /// custom hashing algorithms.
201    ///
202    /// WARNING: This is a lower-level function. For most use cases,
203    /// [`Verifier::verify_multi_proof`], which uses `keccak256` as a hashing
204    /// algorithm, should be enough. Using other hashing algorithm may have
205    /// unexpected results.
206    ///
207    /// The `proof` must contain the sibling hashes one would need to rebuild
208    /// the root starting from `leaves`. `proof_flags` represents whether a
209    /// hash must be computed using a `proof` member. A new root is rebuilt by
210    /// starting from the `leaves` and traversing up the Merkle tree.
211    ///
212    /// The procedure incrementally reconstructs all inner nodes by combining
213    /// a leaf/inner node with either another leaf/inner node or a `proof`
214    /// sibling node, depending on each proof flag being true or false
215    /// respectively, i.e., the `i`-th hash must be computed using the proof if
216    /// `proof_flags[i] == false`.
217    ///
218    /// CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs,
219    /// it is sufficient to ensure that:
220    /// - The tree is complete (but not necessarily perfect).
221    /// - The leaves to be proven are in the opposite order they appear in the
222    ///   tree (i.e., as seen from right to left starting at the deepest layer
223    ///   and continuing at the next layer).
224    ///
225    /// NOTE: This implementation is *not* equivalent to it's Solidity
226    /// counterpart. In Rust, access to uninitialized memory panics, which
227    /// means we don't need to check that the whole proof array has been
228    /// processed. Both implementations will revert for the same inputs, but
229    /// for different reasons. See <https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p>
230    ///
231    /// # Arguments
232    ///
233    /// * `proof` - A slice of hashes that constitute the merkle proof.
234    /// * `proof_flags` - A slice of booleans that determine whether to hash
235    ///   leaves or the proof.
236    /// * `root` - The root of the merkle tree, in bytes.
237    /// * `leaves` - A slice of hashes that constitute the leaves of the merkle
238    ///   tree to be proven, each leaf in bytes.
239    /// * `builder` - A [`BuildHasher`] that represents a hashing algorithm.
240    ///
241    /// # Errors
242    ///
243    /// * [`MultiProofError`] - If the arguments are well-formed, but invalid.
244    ///
245    /// # Examples
246    ///
247    /// ```rust
248    /// use openzeppelin_crypto::{merkle::Verifier, KeccakBuilder};
249    /// use hex_literal::hex;
250    ///
251    /// let root   =  hex!("6deb52b5da8fd108f79fab00341f38d2587896634c646ee52e49f845680a70c8");
252    /// let leaves = [hex!("19ba6c6333e0e9a15bf67523e0676e2f23eb8e574092552d5e888c64a4bb3681"),
253    ///               hex!("c62a8cfa41edc0ef6f6ae27a2985b7d39c7fea770787d7e104696c6e81f64848"),
254    ///               hex!("eba909cf4bb90c6922771d7f126ad0fd11dfde93f3937a196274e1ac20fd2f5b")];
255    /// let proof  = [hex!("9a4f64e953595df82d1b4f570d34c4f4f0cfaf729a61e9d60e83e579e1aa283e"),
256    ///               hex!("8076923e76cf01a7c048400a2304c9a9c23bbbdac3a98ea3946340fdafbba34f")];
257    /// let proof_flags = [false, true, false, true];
258    ///
259    /// let verification =
260    ///     Verifier::verify_multi_proof_with_builder(&proof, &proof_flags, root, &leaves, &KeccakBuilder);
261    /// assert!(verification.unwrap());
262    /// ```
263    pub fn verify_multi_proof_with_builder(
264        proof: &[Bytes32],
265        proof_flags: &[bool],
266        root: Bytes32,
267        leaves: &[Bytes32],
268        builder: &B,
269    ) -> Result<bool, MultiProofError> {
270        let total_hashes = proof_flags.len();
271        if leaves.len() + proof.len() != total_hashes + 1 {
272            return Err(MultiProofError::InvalidTotalHashes);
273        }
274        if total_hashes == 0 {
275            // We can safely assume that either `leaves` or `proof` is not empty
276            // given the previous check. We use `unwrap_or_else` to avoid
277            // eagerly evaluating `proof[0]`, which may panic.
278            let rebuilt_root = *leaves.first().unwrap_or_else(|| &proof[0]);
279            return Ok(root == rebuilt_root);
280        }
281
282        // We need at least one leaf for non-trivial trees
283        if leaves.is_empty() {
284            return Err(MultiProofError::NoLeaves);
285        }
286
287        // `hashes` represents a queue of hashes, our "main queue".
288        let mut hashes = Vec::with_capacity(total_hashes + leaves.len());
289        // Which initially gets populated with the leaves.
290        hashes.extend(leaves);
291        // The `xxx_pos` values are "pointers" to the next value to consume in
292        // each queue. We use them to mimic a queue's pop operation.
293        let mut proof_pos = 0;
294        let mut hashes_pos = 0;
295        // At each step, we compute the next hash using two values:
296        // - A value from the "main queue". Consume all the leaves, then all the
297        //   hashes but the root.
298        // - A value from the "main queue" (merging branches) or a member of the
299        //   `proof`, depending on `flag`.
300        for &flag in proof_flags {
301            let a = hashes[hashes_pos];
302            hashes_pos += 1;
303
304            let b;
305            if flag {
306                b = hashes
307                    .get(hashes_pos)
308                    .ok_or(MultiProofError::InvalidRootChild)?;
309                hashes_pos += 1;
310            } else {
311                b = proof
312                    .get(proof_pos)
313                    .ok_or(MultiProofError::InvalidProofLength)?;
314                proof_pos += 1;
315            }
316
317            let hash = commutative_hash_pair(&a, b, builder.build_hasher());
318            hashes.push(hash);
319        }
320
321        // We know that `total_hashes > 0`.
322        let rebuilt_root = hashes[total_hashes + leaves.len() - 1];
323        Ok(root == rebuilt_root)
324    }
325}
326
327/// An error that occurred while verifying a multi-proof.
328///
329/// TODO: Once <https://github.com/rust-lang/rust/issues/103765> is resolved,
330/// we should derive `core::error::Error`.
331#[derive(core::fmt::Debug, PartialEq)]
332pub enum MultiProofError {
333    /// The proof length does not match the flags.
334    InvalidProofLength,
335    /// Tried to access uninitialized memory.
336    ///
337    /// This happens when the proof is too long, which makes the verification
338    /// procedure try to access uninitialized memory, which may result in an
339    /// invalid root.
340    ///
341    /// For more information see [this vulnerability].
342    ///
343    /// [this vulnerability]: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p
344    InvalidRootChild,
345    /// The number of leaves and proof members does not match the number of
346    /// hashes necessary to complete the verification.
347    InvalidTotalHashes,
348    /// No leaves were provided for a non-trivial tree.
349    NoLeaves,
350}
351
352impl core::fmt::Display for MultiProofError {
353    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
354        let msg = match self {
355            MultiProofError::InvalidProofLength => "invalid multi-proof length",
356            MultiProofError::InvalidRootChild => "invalid root child generated",
357            MultiProofError::InvalidTotalHashes => {
358                "leaves.len() + proof.len() != total_hashes + 1"
359            }
360            MultiProofError::NoLeaves => {
361                "no leaves were provided for a non-trivial tree"
362            }
363        };
364
365        write!(f, "{msg}")
366    }
367}
368
369#[cfg(test)]
370mod tests {
371    //! NOTE: The values used as input for these tests were all generated using
372    //! <https://github.com/OpenZeppelin/merkle-tree>.
373    use hex_literal::hex;
374    use proptest::{prelude::*, prop_compose};
375    use rand::{rng, RngCore};
376
377    use super::{Bytes32, KeccakBuilder, MultiProofError, Verifier};
378    use crate::hash::{commutative_hash_pair, BuildHasher};
379
380    /// Shorthand for declaring variables converted from a hex literal to a
381    /// fixed 32-byte slice.
382    macro_rules! bytes {
383        ($($var:ident = $hex:literal);* $(;)?) => {
384            $(
385                #[allow(non_upper_case_globals)]
386                const $var: Bytes32 = hex!($hex);
387            )*
388        };
389    }
390
391    /// Shorthand for converting from an array of hex literals to an array of
392    /// fixed 32-bytes slices.
393    macro_rules! bytes_array {
394        ($($s:literal),* $(,)?) => {
395            [
396              $(hex!($s),)*
397            ]
398        };
399    }
400
401    prop_compose! {
402        fn valid_merkle_proof(min_proof_len: usize)(
403            leaf: [u8; 32],
404            proof in prop::collection::vec(any::<[u8; 32]>(), min_proof_len..ProptestConfig::default().max_default_size_range),
405        ) -> (Vec<[u8; 32]>, [u8; 32], [u8; 32]) {
406            let mut current = leaf;
407            for &hash in &proof {
408                current = commutative_hash_pair(
409                    &current,
410                    &hash,
411                    KeccakBuilder.build_hasher(),
412                );
413            }
414            let root = current;
415            (proof, root, leaf)
416        }
417    }
418
419    #[test]
420    fn proof_tampering_invalidates() {
421        proptest!(
422            |((proof, root, leaf) in valid_merkle_proof(0),
423             tamper_idx in 0..32usize)| {
424                if let Some(proof_element) = proof.first() {
425                    let mut tampered_proof = proof.clone();
426                    let mut tampered_element = *proof_element;
427                    tampered_element[tamper_idx] =
428                        tampered_element[tamper_idx].wrapping_add(1);
429                    tampered_proof[0] = tampered_element;
430
431                    prop_assert!(!Verifier::verify(&tampered_proof, root, leaf));
432                }
433            }
434        );
435    }
436
437    #[test]
438    fn proof_length_affects_verification() {
439        proptest!(
440            |((proof, root, leaf) in valid_merkle_proof(0),
441             extra_hash: [u8; 32])| {
442                let longer_proof = &[proof.as_slice(), &[extra_hash]].concat();
443                prop_assert!(!Verifier::verify(longer_proof, root, leaf));
444
445                if !proof.is_empty() {
446                    let shorter_proof = &proof[1..];
447                    prop_assert!(!Verifier::verify(shorter_proof, root, leaf));
448                    let shorter_proof = &proof[..proof.len() - 1];
449                    prop_assert!(!Verifier::verify(shorter_proof, root, leaf));
450                }
451            }
452        );
453    }
454
455    #[test]
456    fn proof_consistency() {
457        proptest!(
458            |(proof: Vec<[u8; 32]>,
459             proof_flags: Vec<bool>,
460             root: [u8; 32],
461             // for regular proof
462             leaf: [u8; 32],
463             // for multi-proof
464             leaves: Vec<[u8; 32]>,)| {
465                let result1 = Verifier::verify(&proof, root, leaf);
466                let result2 = Verifier::verify(&proof, root, leaf);
467                prop_assert_eq!(result1, result2);
468
469                // ensure proof_flags length is always <= proof.len()
470                let proof_flags =
471                proof_flags.into_iter().take(proof.len()).collect::<Vec<_>>();
472
473                let result1 = Verifier::verify_multi_proof(
474                    &proof,
475                    &proof_flags,
476                    root,
477                    &leaves,
478                );
479                let result2 = Verifier::verify_multi_proof(
480                    &proof,
481                    &proof_flags,
482                    root,
483                    &leaves,
484                );
485                prop_assert_eq!(result1, result2);
486            }
487        );
488    }
489
490    #[test]
491    fn single_leaf_equals_regular_verify() {
492        proptest!(|((proof, root, leaf) in valid_merkle_proof(0))| {
493            let proof_flags = vec![false; proof.len()];
494            let multi_result = Verifier::verify_multi_proof(
495                &proof,
496                &proof_flags,
497                root,
498                &[leaf],
499            );
500            let regular_result = Verifier::verify(&proof, root, leaf);
501
502            let multi_result = multi_result.unwrap();
503            prop_assert_eq!(multi_result, regular_result);
504        });
505    }
506
507    #[test]
508    fn zero_length_proof_with_matching_leaf_and_root() {
509        let root = [0u8; 32];
510        let leaf = root;
511        assert!(Verifier::verify(&[], root, leaf));
512    }
513
514    #[test]
515    fn multi_proof_empty_flags() {
516        let root = [0u8; 32];
517        let leaves = vec![[1u8; 32]];
518        let proof = vec![[2u8; 32]];
519
520        let result = Verifier::verify_multi_proof(&proof, &[], root, &leaves);
521        assert!(result.is_err());
522    }
523
524    #[test]
525    fn multi_proof_minimum_valid_case() {
526        let root = [0u8; 32];
527        let leaves = vec![[0u8; 32]];
528        let result = Verifier::verify_multi_proof(&[], &[], root, &leaves);
529        assert!(result.is_ok());
530    }
531
532    #[test]
533    fn verifies_valid_proofs() {
534        // ```js
535        // const merkleTree = StandardMerkleTree.of(
536        //   toElements('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='),
537        //   ['string'],
538        // );
539        //
540        // const root  = merkleTree.root;
541        // const hash  = merkleTree.leafHash(['A']);
542        // const proof = merkleTree.getProof(['A']);
543        // ```
544        bytes! {
545            root   = "b89eb120147840e813a77109b44063488a346b4ca15686185cf314320560d3f3";
546            leaf_a = "6efbf77e320741a027b50f02224545461f97cd83762d5fbfeb894b9eb3287c16";
547            leaf_b = "7051e21dd45e25ed8c605a53da6f77de151dcbf47b0e3ced3c5d8b61f4a13dbc";
548        };
549        let proof = bytes_array! {
550            "7051e21dd45e25ed8c605a53da6f77de151dcbf47b0e3ced3c5d8b61f4a13dbc",
551            "1629d3b5b09b30449d258e35bbd09dd5e8a3abb91425ef810dc27eef995f7490",
552            "633d21baee4bbe5ed5c51ac0c68f7946b8f28d2937f0ca7ef5e1ea9dbda52e7a",
553            "8a65d3006581737a3bab46d9e4775dbc1821b1ea813d350a13fcd4f15a8942ec",
554            "d6c3f3e36cd23ba32443f6a687ecea44ebfe2b8759a62cccf7759ec1fb563c76",
555            "276141cd72b9b81c67f7182ff8a550b76eb96de9248a3ec027ac048c79649115",
556        };
557
558        let verification = Verifier::verify(&proof, root, leaf_a);
559        assert!(verification);
560
561        let builder = KeccakBuilder.build_hasher();
562        let no_such_leaf = commutative_hash_pair(&leaf_a, &leaf_b, builder);
563        let proof = &proof[1..];
564        let verification = Verifier::verify(proof, root, no_such_leaf);
565        assert!(verification);
566    }
567
568    #[test]
569    fn rejects_invalid_proofs() {
570        // ```js
571        // const correctMerkleTree = StandardMerkleTree.of(toElements('abc'), ['string']);
572        // const otherMerkleTree = StandardMerkleTree.of(toElements('def'), ['string']);
573        //
574        // const root = correctMerkleTree.root;
575        // const leaf = correctMerkleTree.leafHash(['a']);
576        // const proof = otherMerkleTree.getProof(['d']);
577        // ```
578        bytes! {
579            root  = "f2129b5a697531ef818f644564a6552b35c549722385bc52aa7fe46c0b5f46b1";
580            leaf  = "9c15a6a0eaeed500fd9eed4cbeab71f797cefcc67bfd46683e4d2e6ff7f06d1c";
581            proof = "7b0c6cd04b82bfc0e250030a5d2690c52585e0cc6a4f3bc7909d7723b0236ece";
582        };
583
584        let verification = Verifier::verify(&[proof], root, leaf);
585        assert!(!verification);
586    }
587
588    #[test]
589    fn rejects_proofs_with_invalid_length() {
590        // ```js
591        // const merkleTree = StandardMerkleTree.of(toElements('abc'), ['string']);
592        //
593        // const root = merkleTree.root;
594        // const leaf = merkleTree.leafHash(['a']);
595        // const proof = merkleTree.getProof(['a']);
596        // ```
597        bytes! {
598            root = "f2129b5a697531ef818f644564a6552b35c549722385bc52aa7fe46c0b5f46b1";
599            leaf = "9c15a6a0eaeed500fd9eed4cbeab71f797cefcc67bfd46683e4d2e6ff7f06d1c";
600        };
601        let proof = bytes_array! {
602            "19ba6c6333e0e9a15bf67523e0676e2f23eb8e574092552d5e888c64a4bb3681",
603            "9cf5a63718145ba968a01c1d557020181c5b252f665cf7386d370eddb176517b",
604        };
605
606        let bad_proof = &proof[..1];
607        let verification = Verifier::verify(bad_proof, root, leaf);
608        assert!(!verification);
609    }
610
611    #[test]
612    fn verifies_valid_multi_proof() {
613        // ```js
614        // const merkleTree = StandardMerkleTree.of(toElements('abcdef'), ['string']);
615        //
616        // const root = merkleTree.root;
617        // const { proof, proofFlags, leaves } = merkleTree.getMultiProof(toElements('bdf'));
618        // const hashes = leaves.map(e => merkleTree.leafHash(e));
619        // ```
620        bytes! {
621            root = "6deb52b5da8fd108f79fab00341f38d2587896634c646ee52e49f845680a70c8";
622        };
623        let leaves = bytes_array! {
624            "19ba6c6333e0e9a15bf67523e0676e2f23eb8e574092552d5e888c64a4bb3681",
625            "c62a8cfa41edc0ef6f6ae27a2985b7d39c7fea770787d7e104696c6e81f64848",
626            "eba909cf4bb90c6922771d7f126ad0fd11dfde93f3937a196274e1ac20fd2f5b",
627        };
628        let proof = bytes_array! {
629            "9a4f64e953595df82d1b4f570d34c4f4f0cfaf729a61e9d60e83e579e1aa283e",
630            "8076923e76cf01a7c048400a2304c9a9c23bbbdac3a98ea3946340fdafbba34f",
631        };
632
633        let proof_flags = [false, true, false, true];
634        let verification =
635            Verifier::verify_multi_proof(&proof, &proof_flags, root, &leaves);
636        assert!(verification.unwrap());
637    }
638
639    #[test]
640    fn rejects_invalid_multi_proof() {
641        // ```js
642        // const merkleTree = StandardMerkleTree.of(toElements('abcdef'), ['string']);
643        // const otherMerkleTree = StandardMerkleTree.of(toElements('ghi'), ['string']);
644        //
645        // const root = merkleTree.root;
646        // const { proof, proofFlags, leaves } = otherMerkleTree.getMultiProof(toElements('ghi'));
647        // const hashes = leaves.map(e => merkleTree.leafHash(e));
648        // ```
649        bytes! {
650            root = "6deb52b5da8fd108f79fab00341f38d2587896634c646ee52e49f845680a70c8";
651        };
652        let leaves = bytes_array! {
653            "34e6ce3d0d73f6bff2ee1e865833d58e283570976d70b05f45c989ef651ef742",
654            "aa28358fb75b314c899e16d7975e029d18b4457fd8fd831f2e6c17ffd17a1d7e",
655            "e0fd7e6916ff95d933525adae392a17e247819ebecc2e63202dfec7005c60560",
656        };
657        let proof = [];
658        let proof_flags = [true, true];
659
660        let verification =
661            Verifier::verify_multi_proof(&proof, &proof_flags, root, &leaves);
662        assert!(!verification.unwrap());
663    }
664
665    #[test]
666    fn multi_proof_invalid_total_hashes_length() {
667        // ```js
668        // const merkleTree = StandardMerkleTree.of(toElements('abcd'), ['string']);
669        //
670        // const root = merkleTree.root;
671        // const hashA = merkleTree.leafHash(['a']);
672        // const hashB = merkleTree.leafHash(['b']);
673        // const hashCD = hashPair(
674        //   ethers.toBeArray(merkleTree.leafHash(['c'])),
675        //   ethers.toBeArray(merkleTree.leafHash(['d'])),
676        // );
677        // const hashE = merkleTree.leafHash(['e']); // incorrect (not part of the tree)
678        // const fill = ethers.randomBytes(32);
679        // ```
680        bytes! {
681            root    = "8f7234e8cfe39c08ca84a3a3e3274f574af26fd15165fe29e09cbab742daccd9";
682            hash_a  = "9c15a6a0eaeed500fd9eed4cbeab71f797cefcc67bfd46683e4d2e6ff7f06d1c";
683            hash_b  = "19ba6c6333e0e9a15bf67523e0676e2f23eb8e574092552d5e888c64a4bb3681";
684            hash_cd = "03707d7802a71ca56a8ad8028da98c4f1dbec55b31b4a25d536b5309cc20eda9";
685            hash_e  = "9a4f64e953595df82d1b4f570d34c4f4f0cfaf729a61e9d60e83e579e1aa283e";
686        };
687
688        let mut random_bytes = [0u8; 32];
689        rng().fill_bytes(&mut random_bytes);
690
691        let fill = Bytes32::from(random_bytes);
692        let proof = [hash_b, fill, hash_cd];
693        let proof_flags = [false, false, false];
694        let leaves = [hash_a, hash_e];
695
696        let err =
697            Verifier::verify_multi_proof(&proof, &proof_flags, root, &leaves)
698                .unwrap_err();
699        assert!(matches!(err, MultiProofError::InvalidTotalHashes));
700    }
701
702    #[test]
703    fn multi_proof_invalid_proof_length() {
704        // ```js
705        // const merkleTree = StandardMerkleTree.of(toElements('abcd'), ['string']);
706        //
707        // const root = merkleTree.root;
708        // const hashA = merkleTree.leafHash(['a']);
709        // const hashB = merkleTree.leafHash(['b']);
710        // const hashCD = hashPair(
711        //   ethers.toBeArray(merkleTree.leafHash(['c'])),
712        //   ethers.toBeArray(merkleTree.leafHash(['d'])),
713        // );
714        // const hashE = merkleTree.leafHash(['e']); // incorrect (not part of the tree)
715        // const fill = ethers.randomBytes(32);
716        // ```
717        bytes! {
718            root    = "8f7234e8cfe39c08ca84a3a3e3274f574af26fd15165fe29e09cbab742daccd9";
719            hash_a  = "9c15a6a0eaeed500fd9eed4cbeab71f797cefcc67bfd46683e4d2e6ff7f06d1c";
720            hash_b  = "19ba6c6333e0e9a15bf67523e0676e2f23eb8e574092552d5e888c64a4bb3681";
721            hash_cd = "03707d7802a71ca56a8ad8028da98c4f1dbec55b31b4a25d536b5309cc20eda9";
722            hash_e  = "9a4f64e953595df82d1b4f570d34c4f4f0cfaf729a61e9d60e83e579e1aa283e";
723        };
724
725        let mut random_bytes = [0u8; 32];
726        rng().fill_bytes(&mut random_bytes);
727
728        let fill = Bytes32::from(random_bytes);
729        let proof = [hash_b, fill, hash_cd];
730        let proof_flags = [false, false, false, false];
731        let leaves = [hash_e, hash_a];
732
733        let err =
734            Verifier::verify_multi_proof(&proof, &proof_flags, root, &leaves)
735                .unwrap_err();
736        assert!(matches!(err, MultiProofError::InvalidProofLength));
737    }
738
739    #[test]
740    fn verifies_empty_leaves_multi_proof() {
741        // ```js
742        // const merkleTree = StandardMerkleTree.of(toElements('abcd'), ['string']);
743        //
744        // const root = merkleTree.root;
745        // ```
746        bytes!(root = "8f7234e8cfe39c08ca84a3a3e3274f574af26fd15165fe29e09cbab742daccd9");
747        let proof = [root];
748        let proof_flags = [];
749        let leaves = [];
750
751        let verification =
752            Verifier::verify_multi_proof(&proof, &proof_flags, root, &leaves);
753        assert!(verification.unwrap());
754    }
755
756    #[test]
757    /// Errors when processing manipulated proofs with a zero-value node at
758    /// depth 1.
759    fn errors_manipulated_multi_proof() {
760        // Create a merkle tree that contains a zero leaf at depth 1
761        //
762        // Taken from https://github.com/advisories/GHSA-wprv-93r4-jj2p
763        //
764        // ```js
765        // const { MerkleTree } = require('merkletreejs'); // v0.2.32
766        // const keccak256 = require('keccak256'); // v1.0.6
767        //
768        // const leaves = [keccak256('real leaf'), Buffer.alloc(32, 0)];
769        // const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true });
770        // const root = merkleTree.getRoot();
771        // ```
772        bytes! {
773            root = "f2d552e1e4c59d4f0fa2b80859febc9e4bdc915dff37c56c858550d8b64659a5";
774            leaf = "5e941ddd8f313c0b39f92562c0eca709c3d91360965d396aaef584b3fa76889a"; // 'real leaf'
775        };
776        let malicious_leaves = bytes_array! {
777            "1f23ad5fc0ee6ccbe2f3d30df856758f05ad9d03408a51a99c1c9f0854309db2",
778            "4e7e8301f5d206748d1c4f822e3564ddb1124f86591a839f58dfc2f007983b61",
779            "613994f4e324d0667c07857cd5d147994bc917da5d07ee63fc3f0a1fe8a18e34",
780        };
781        let malicious_proof = [leaf, leaf];
782        let malicious_proof_flags = [true, true, false];
783
784        let verification = Verifier::verify_multi_proof(
785            &malicious_proof,
786            &malicious_proof_flags,
787            root,
788            &malicious_leaves,
789        );
790        assert!(verification.is_err());
791    }
792
793    #[test]
794    fn verify_empty_proof_should_mean_leaf_equal_to_root() {
795        // ```js
796        // const merkleTree = StandardMerkleTree.of(toElements('abc'), ['string']);
797        //
798        // const root = merkleTree.root;
799        // const leaf = merkleTree.leafHash(['a']);
800        // const proof = merkleTree.getProof(['a']);
801        // ```
802        bytes! {
803            root = "f2129b5a697531ef818f644564a6552b35c549722385bc52aa7fe46c0b5f46b1";
804            leaf = "9c15a6a0eaeed500fd9eed4cbeab71f797cefcc67bfd46683e4d2e6ff7f06d1c";
805        };
806        let proof = [];
807
808        // valid if root == leaf
809        assert!(Verifier::verify(&proof, root, root));
810
811        // invalid if root != leaf
812        assert!(!Verifier::verify(&proof, root, leaf));
813    }
814}