1#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(missing_docs)]
20
21#[cfg(not(feature = "std"))]
34extern crate alloc;
35#[cfg(not(feature = "std"))]
36use alloc::vec;
37#[cfg(not(feature = "std"))]
38use alloc::vec::Vec;
39
40use codec::{Decode, Encode};
41use hash_db::Hasher;
42
43pub fn merkle_root<H, I>(leaves: I) -> H::Out
49where
50 H: Hasher,
51 H::Out: Default + AsRef<[u8]>,
52 I: IntoIterator,
53 I::Item: AsRef<[u8]>,
54{
55 let iter = leaves.into_iter().map(|l| <H as Hasher>::hash(l.as_ref()));
56 merkelize::<H, _, _>(iter, &mut ()).into()
57}
58
59pub fn merkle_root_raw<H, I>(leaves: I) -> H::Out
68where
69 H: Hasher,
70 H::Out: Default + AsRef<[u8]>,
71 I: IntoIterator<Item = H::Out>,
72{
73 merkelize::<H, _, _>(leaves.into_iter(), &mut ()).into()
74}
75
76fn merkelize<H, V, I>(leaves: I, visitor: &mut V) -> H::Out
77where
78 H: Hasher,
79 H::Out: Default + AsRef<[u8]>,
80 V: Visitor<H::Out>,
81 I: Iterator<Item = H::Out>,
82{
83 let upper = Vec::with_capacity((leaves.size_hint().1.unwrap_or(0).saturating_add(1)) / 2);
84 let mut next = match merkelize_row::<H, _, _>(leaves, upper, visitor) {
85 Ok(root) => return root,
86 Err(next) if next.is_empty() => return H::Out::default(),
87 Err(next) => next,
88 };
89
90 let mut upper = Vec::with_capacity((next.len().saturating_add(1)) / 2);
91 loop {
92 visitor.move_up();
93
94 match merkelize_row::<H, _, _>(next.drain(..), upper, visitor) {
95 Ok(root) => return root,
96 Err(t) => {
97 upper = next;
99 next = t;
100 },
101 };
102 }
103}
104
105#[derive(Debug, PartialEq, Eq, Encode, Decode)]
109pub struct MerkleProof<H, L> {
110 pub root: H,
112 pub proof: Vec<H>,
117 pub number_of_leaves: u32,
122 pub leaf_index: u32,
124 pub leaf: L,
126}
127
128trait Visitor<T> {
133 fn move_up(&mut self);
135
136 fn visit(&mut self, index: u32, left: &Option<T>, right: &Option<T>);
143}
144
145impl<T> Visitor<T> for () {
147 fn move_up(&mut self) {}
148 fn visit(&mut self, _index: u32, _left: &Option<T>, _right: &Option<T>) {}
149}
150
151fn proof_capacity(number_of_leaves: u32) -> usize {
153 number_of_leaves
155 .saturating_sub(1)
156 .checked_ilog2()
157 .map_or(0, |log| log as usize + 1)
158}
159
160struct ProofCollection<T> {
162 proof: Vec<T>,
163 position: u32,
164}
165
166impl<T> ProofCollection<T> {
167 fn new(position: u32, number_of_leaves: u32) -> Self {
168 ProofCollection { proof: Vec::with_capacity(proof_capacity(number_of_leaves)), position }
170 }
171}
172
173impl<T: Copy> Visitor<T> for ProofCollection<T> {
174 fn move_up(&mut self) {
175 self.position /= 2;
176 }
177
178 fn visit(&mut self, index: u32, left: &Option<T>, right: &Option<T>) {
179 if self.position == index {
181 if let Some(right) = right {
182 self.proof.push(*right);
183 }
184 }
185 if self.position == index + 1 {
187 if let Some(left) = left {
188 self.proof.push(*left);
189 }
190 }
191 }
192}
193
194pub fn merkle_proof<H, I, T>(leaves: I, leaf_index: u32) -> MerkleProof<H::Out, T>
205where
206 H: Hasher,
207 H::Out: Default + Copy + AsRef<[u8]>,
208 I: IntoIterator<Item = T>,
209 I::IntoIter: ExactSizeIterator,
210 T: AsRef<[u8]>,
211{
212 let mut leaf = None;
213 let iter = leaves.into_iter().enumerate().map(|(idx, l)| {
214 let hash = <H as Hasher>::hash(l.as_ref());
215 if idx as u32 == leaf_index {
216 leaf = Some(l);
217 }
218 hash
219 });
220
221 let number_of_leaves = iter.len() as u32;
222 let mut collect_proof = ProofCollection::new(leaf_index, number_of_leaves);
223
224 let root = merkelize::<H, _, _>(iter, &mut collect_proof);
225 let leaf = leaf.expect("Requested `leaf_index` is greater than number of leaves.");
226
227 #[cfg(feature = "debug")]
228 log::debug!(
229 "[merkle_proof] Proof: {:?}",
230 collect_proof
231 .proof
232 .iter()
233 .map(|s| array_bytes::bytes2hex("", s))
234 .collect::<Vec<_>>()
235 );
236
237 MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf }
238}
239
240pub fn merkle_proof_raw<H, I>(leaves: I, leaf_index: u32) -> MerkleProof<H::Out, H::Out>
254where
255 H: Hasher,
256 H::Out: Default + Copy + AsRef<[u8]>,
257 I: IntoIterator<Item = H::Out>,
258 I::IntoIter: ExactSizeIterator,
259{
260 let mut leaf = None;
261 let iter = leaves.into_iter().enumerate().map(|(idx, l)| {
262 let hash = l;
263 if idx as u32 == leaf_index {
264 leaf = Some(l);
265 }
266 hash
267 });
268
269 let number_of_leaves = iter.len() as u32;
270 let mut collect_proof = ProofCollection::new(leaf_index, number_of_leaves);
271
272 let root = merkelize::<H, _, _>(iter, &mut collect_proof);
273 let leaf = leaf.expect("Requested `leaf_index` is greater than number of leaves.");
274
275 #[cfg(feature = "debug")]
276 log::debug!(
277 "[merkle_proof] Proof: {:?}",
278 collect_proof
279 .proof
280 .iter()
281 .map(|s| array_bytes::bytes2hex("", s))
282 .collect::<Vec<_>>()
283 );
284
285 MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf }
286}
287
288#[derive(Debug, PartialEq, Eq)]
293pub enum Leaf<'a, H> {
294 Value(&'a [u8]),
296 Hash(H),
298}
299
300impl<'a, H, T: AsRef<[u8]>> From<&'a T> for Leaf<'a, H> {
301 fn from(v: &'a T) -> Self {
302 Leaf::Value(v.as_ref())
303 }
304}
305
306pub fn verify_proof<'a, H, P, L>(
314 root: &'a H::Out,
315 proof: P,
316 number_of_leaves: u32,
317 leaf_index: u32,
318 leaf: L,
319) -> bool
320where
321 H: Hasher,
322 H::Out: PartialEq + AsRef<[u8]>,
323 P: IntoIterator<Item = H::Out>,
324 L: Into<Leaf<'a, H::Out>>,
325{
326 if leaf_index >= number_of_leaves {
327 return false;
328 }
329
330 let leaf_hash = match leaf.into() {
331 Leaf::Value(content) => <H as Hasher>::hash(content),
332 Leaf::Hash(hash) => hash,
333 };
334
335 let hash_len = <H as Hasher>::LENGTH;
336 let mut combined = vec![0_u8; hash_len * 2];
337 let mut position = leaf_index;
338 let mut width = number_of_leaves;
339 let computed = proof.into_iter().fold(leaf_hash, |a, b| {
340 if position % 2 == 1 || position + 1 == width {
341 combined[..hash_len].copy_from_slice(&b.as_ref());
342 combined[hash_len..].copy_from_slice(&a.as_ref());
343 } else {
344 combined[..hash_len].copy_from_slice(&a.as_ref());
345 combined[hash_len..].copy_from_slice(&b.as_ref());
346 }
347 let hash = <H as Hasher>::hash(&combined);
348 #[cfg(feature = "debug")]
349 log::debug!(
350 "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash",
351 array_bytes::bytes2hex("", a),
352 array_bytes::bytes2hex("", b),
353 array_bytes::bytes2hex("", hash),
354 array_bytes::bytes2hex("", &combined)
355 );
356 position /= 2;
357 width = ((width - 1) / 2) + 1;
358 hash
359 });
360
361 root == &computed
362}
363
364fn merkelize_row<H, V, I>(
370 mut iter: I,
371 mut next: Vec<H::Out>,
372 visitor: &mut V,
373) -> Result<H::Out, Vec<H::Out>>
374where
375 H: Hasher,
376 H::Out: AsRef<[u8]>,
377 V: Visitor<H::Out>,
378 I: Iterator<Item = H::Out>,
379{
380 #[cfg(feature = "debug")]
381 log::debug!("[merkelize_row]");
382 next.clear();
383
384 let hash_len = <H as Hasher>::LENGTH;
385 let mut index = 0;
386 let mut combined = vec![0_u8; hash_len * 2];
387 loop {
388 let a = iter.next();
389 let b = iter.next();
390 visitor.visit(index, &a, &b);
391
392 #[cfg(feature = "debug")]
393 log::debug!(
394 " {:?}\n {:?}",
395 a.as_ref().map(|s| array_bytes::bytes2hex("", s)),
396 b.as_ref().map(|s| array_bytes::bytes2hex("", s))
397 );
398
399 index += 2;
400 match (a, b) {
401 (Some(a), Some(b)) => {
402 combined[..hash_len].copy_from_slice(a.as_ref());
403 combined[hash_len..].copy_from_slice(b.as_ref());
404
405 next.push(<H as Hasher>::hash(&combined));
406 },
407 (Some(a), None) if !next.is_empty() => {
409 next.push(a);
410 },
411 (Some(a), None) => return Ok(a),
413 _ => {
415 #[cfg(feature = "debug")]
416 log::debug!(
417 "[merkelize_row] Next: {:?}",
418 next.iter().map(|s| array_bytes::bytes2hex("", s)).collect::<Vec<_>>()
419 );
420 return Err(next);
421 },
422 }
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429 use sp_core::H256;
430 use sp_runtime::traits::Keccak256;
431
432 #[test]
433 fn should_generate_empty_root() {
434 let data: Vec<[u8; 1]> = Default::default();
436
437 let out = merkle_root::<Keccak256, _>(data);
439
440 assert_eq!(
442 array_bytes::bytes2hex("", out),
443 "0000000000000000000000000000000000000000000000000000000000000000"
444 );
445 }
446
447 #[test]
448 fn should_generate_single_root() {
449 let data = vec![array_bytes::hex2array_unchecked::<_, 20>(
451 "E04CC55ebEE1cBCE552f250e85c57B70B2E2625b",
452 )];
453
454 let out = merkle_root::<Keccak256, _>(data);
456
457 assert_eq!(
459 array_bytes::bytes2hex("", out),
460 "aeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7"
461 );
462 }
463
464 #[test]
465 fn should_generate_root_pow_2() {
466 let data = vec![
468 array_bytes::hex2array_unchecked::<_, 20>("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"),
469 array_bytes::hex2array_unchecked::<_, 20>("25451A4de12dcCc2D166922fA938E900fCc4ED24"),
470 ];
471
472 let out = merkle_root::<Keccak256, _>(data);
474
475 assert_eq!(
477 array_bytes::bytes2hex("", out),
478 "697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402"
479 );
480 }
481
482 #[test]
483 fn should_generate_root_complex() {
484 let test = |root, data| {
485 assert_eq!(array_bytes::bytes2hex("", &merkle_root::<Keccak256, _>(data)), root);
486 };
487
488 test(
489 "aff1208e69c9e8be9b584b07ebac4e48a1ee9d15ce3afe20b77a4d29e4175aa3",
490 vec!["a", "b", "c"],
491 );
492
493 test(
494 "b8912f7269068901f231a965adfefbc10f0eedcfa61852b103efd54dac7db3d7",
495 vec!["a", "b", "a"],
496 );
497
498 test(
499 "dc8e73fe6903148ff5079baecc043983625c23b39f31537e322cd0deee09fa9c",
500 vec!["a", "b", "a", "b"],
501 );
502
503 test(
504 "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239",
505 vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"],
506 );
507 }
508
509 #[test]
510 fn should_generate_and_verify_proof_simple() {
511 let data = vec!["a", "b", "c"];
513
514 let proof0 = merkle_proof::<Keccak256, _, _>(data.clone(), 0);
516 assert!(verify_proof::<Keccak256, _, _>(
517 &proof0.root,
518 proof0.proof.clone(),
519 data.len() as _,
520 proof0.leaf_index,
521 &proof0.leaf,
522 ));
523
524 let proof1 = merkle_proof::<Keccak256, _, _>(data.clone(), 1);
525 assert!(verify_proof::<Keccak256, _, _>(
526 &proof1.root,
527 proof1.proof,
528 data.len() as _,
529 proof1.leaf_index,
530 &proof1.leaf,
531 ));
532
533 let proof2 = merkle_proof::<Keccak256, _, _>(data.clone(), 2);
534 assert!(verify_proof::<Keccak256, _, _>(
535 &proof2.root,
536 proof2.proof,
537 data.len() as _,
538 proof2.leaf_index,
539 &proof2.leaf
540 ));
541
542 assert_eq!(
544 array_bytes::bytes2hex("", &proof0.root),
545 array_bytes::bytes2hex("", &proof1.root)
546 );
547 assert_eq!(
548 array_bytes::bytes2hex("", &proof2.root),
549 array_bytes::bytes2hex("", &proof1.root)
550 );
551
552 assert!(!verify_proof::<Keccak256, _, _>(
553 &array_bytes::hex2array_unchecked(
554 "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239"
555 )
556 .into(),
557 proof0.proof,
558 data.len() as _,
559 proof0.leaf_index,
560 &proof0.leaf
561 ));
562
563 assert!(!verify_proof::<Keccak256, _, _>(
564 &proof0.root.into(),
565 vec![],
566 data.len() as _,
567 proof0.leaf_index,
568 &proof0.leaf
569 ));
570 }
571
572 #[test]
573 fn should_generate_and_verify_proof_complex() {
574 let data = vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
576
577 for l in 0..data.len() as u32 {
578 let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
580 assert!(verify_proof::<Keccak256, _, _>(
582 &proof.root,
583 proof.proof,
584 data.len() as _,
585 proof.leaf_index,
586 &proof.leaf
587 ));
588 }
589 }
590
591 #[test]
592 fn should_generate_and_verify_proof_large() {
593 let mut data = vec![];
595 for i in 1..16 {
596 for c in 'a'..'z' {
597 if !(c as usize).is_multiple_of(i) {
598 data.push(c.to_string());
599 }
600 }
601
602 for l in 0..data.len() as u32 {
603 let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
605 assert!(verify_proof::<Keccak256, _, _>(
607 &proof.root,
608 proof.proof,
609 data.len() as _,
610 proof.leaf_index,
611 &proof.leaf
612 ));
613 }
614 }
615 }
616
617 #[test]
618 fn should_generate_and_verify_proof_large_tree() {
619 let mut data = vec![];
621 for i in 0..6000 {
622 data.push(format!("{}", i));
623 }
624
625 for l in (0..data.len() as u32).step_by(13) {
626 let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
628 assert!(verify_proof::<Keccak256, _, _>(
630 &proof.root,
631 proof.proof,
632 data.len() as _,
633 proof.leaf_index,
634 &proof.leaf
635 ));
636 }
637 }
638
639 #[test]
640 #[should_panic]
641 fn should_panic_on_invalid_leaf_index() {
642 merkle_proof::<Keccak256, _, _>(vec!["a"], 5);
643 }
644
645 #[test]
646 fn should_generate_and_verify_proof_on_test_data() {
647 let addresses = vec![
648 "0x9aF1Ca5941148eB6A3e9b9C741b69738292C533f",
649 "0xDD6ca953fddA25c496165D9040F7F77f75B75002",
650 "0x60e9C47B64Bc1C7C906E891255EaEC19123E7F42",
651 "0xfa4859480Aa6D899858DE54334d2911E01C070df",
652 "0x19B9b128470584F7209eEf65B69F3624549Abe6d",
653 "0xC436aC1f261802C4494504A11fc2926C726cB83b",
654 "0xc304C8C2c12522F78aD1E28dD86b9947D7744bd0",
655 "0xDa0C2Cba6e832E55dE89cF4033affc90CC147352",
656 "0xf850Fd22c96e3501Aad4CDCBf38E4AEC95622411",
657 "0x684918D4387CEb5E7eda969042f036E226E50642",
658 "0x963F0A1bFbb6813C0AC88FcDe6ceB96EA634A595",
659 "0x39B38ad74b8bCc5CE564f7a27Ac19037A95B6099",
660 "0xC2Dec7Fdd1fef3ee95aD88EC8F3Cd5bd4065f3C7",
661 "0x9E311f05c2b6A43C2CCF16fB2209491BaBc2ec01",
662 "0x927607C30eCE4Ef274e250d0bf414d4a210b16f0",
663 "0x98882bcf85E1E2DFF780D0eB360678C1cf443266",
664 "0xFBb50191cd0662049E7C4EE32830a4Cc9B353047",
665 "0x963854fc2C358c48C3F9F0A598B9572c581B8DEF",
666 "0xF9D7Bc222cF6e3e07bF66711e6f409E51aB75292",
667 "0xF2E3fd32D063F8bBAcB9e6Ea8101C2edd899AFe6",
668 "0x407a5b9047B76E8668570120A96d580589fd1325",
669 "0xEAD9726FAFB900A07dAd24a43AE941d2eFDD6E97",
670 "0x42f5C8D9384034A9030313B51125C32a526b6ee8",
671 "0x158fD2529Bc4116570Eb7C80CC76FEf33ad5eD95",
672 "0x0A436EE2E4dEF3383Cf4546d4278326Ccc82514E",
673 "0x34229A215db8FeaC93Caf8B5B255e3c6eA51d855",
674 "0xEb3B7CF8B1840242CB98A732BA464a17D00b5dDF",
675 "0x2079692bf9ab2d6dc7D79BBDdEE71611E9aA3B72",
676 "0x46e2A67e5d450e2Cf7317779f8274a2a630f3C9B",
677 "0xA7Ece4A5390DAB18D08201aE18800375caD78aab",
678 "0x15E1c0D24D62057Bf082Cb2253dA11Ef0d469570",
679 "0xADDEF4C9b5687Eb1F7E55F2251916200A3598878",
680 "0xe0B16Fb96F936035db2b5A68EB37D470fED2f013",
681 "0x0c9A84993feaa779ae21E39F9793d09e6b69B62D",
682 "0x3bc4D5148906F70F0A7D1e2756572655fd8b7B34",
683 "0xFf4675C26903D5319795cbd3a44b109E7DDD9fDe",
684 "0xCec4450569A8945C6D2Aba0045e4339030128a92",
685 "0x85f0584B10950E421A32F471635b424063FD8405",
686 "0xb38bEe7Bdc0bC43c096e206EFdFEad63869929E3",
687 "0xc9609466274Fef19D0e58E1Ee3b321D5C141067E",
688 "0xa08EA868cF75268E7401021E9f945BAe73872ecc",
689 "0x67C9Cb1A29E964Fe87Ff669735cf7eb87f6868fE",
690 "0x1B6BEF636aFcdd6085cD4455BbcC93796A12F6E2",
691 "0x46B37b243E09540b55cF91C333188e7D5FD786dD",
692 "0x8E719E272f62Fa97da93CF9C941F5e53AA09e44a",
693 "0xa511B7E7DB9cb24AD5c89fBb6032C7a9c2EfA0a5",
694 "0x4D11FDcAeD335d839132AD450B02af974A3A66f8",
695 "0xB8cf790a5090E709B4619E1F335317114294E17E",
696 "0x7f0f57eA064A83210Cafd3a536866ffD2C5eDCB3",
697 "0xC03C848A4521356EF800e399D889e9c2A25D1f9E",
698 "0xC6b03DF05cb686D933DD31fCa5A993bF823dc4FE",
699 "0x58611696b6a8102cf95A32c25612E4cEF32b910F",
700 "0x2ed4bC7197AEF13560F6771D930Bf907772DE3CE",
701 "0x3C5E58f334306be029B0e47e119b8977B2639eb4",
702 "0x288646a1a4FeeC560B349d210263c609aDF649a6",
703 "0xb4F4981E0d027Dc2B3c86afA0D0fC03d317e83C0",
704 "0xaAE4A87F8058feDA3971f9DEd639Ec9189aA2500",
705 "0x355069DA35E598913d8736E5B8340527099960b8",
706 "0x3cf5A0F274cd243C0A186d9fCBdADad089821B93",
707 "0xca55155dCc4591538A8A0ca322a56EB0E4aD03C4",
708 "0xE824D0268366ec5C4F23652b8eD70D552B1F2b8B",
709 "0x84C3e9B25AE8a9b39FF5E331F9A597F2DCf27Ca9",
710 "0xcA0018e278751De10d26539915d9c7E7503432FE",
711 "0xf13077dE6191D6c1509ac7E088b8BE7Fe656c28b",
712 "0x7a6bcA1ec9Db506e47ac6FD86D001c2aBc59C531",
713 "0xeA7f9A2A9dd6Ba9bc93ca615C3Ddf26973146911",
714 "0x8D0d8577e16F8731d4F8712BAbFa97aF4c453458",
715 "0xB7a7855629dF104246997e9ACa0E6510df75d0ea",
716 "0x5C1009BDC70b0C8Ab2e5a53931672ab448C17c89",
717 "0x40B47D1AfefEF5eF41e0789F0285DE7b1C31631C",
718 "0x5086933d549cEcEB20652CE00973703CF10Da373",
719 "0xeb364f6FE356882F92ae9314fa96116Cf65F47d8",
720 "0xdC4D31516A416cEf533C01a92D9a04bbdb85EE67",
721 "0x9b36E086E5A274332AFd3D8509e12ca5F6af918d",
722 "0xBC26394fF36e1673aE0608ce91A53B9768aD0D76",
723 "0x81B5AB400be9e563fA476c100BE898C09966426c",
724 "0x9d93C8ae5793054D28278A5DE6d4653EC79e90FE",
725 "0x3B8E75804F71e121008991E3177fc942b6c28F50",
726 "0xC6Eb5886eB43dD473f5BB4e21e56E08dA464D9B4",
727 "0xfdf1277b71A73c813cD0e1a94B800f4B1Db66DBE",
728 "0xc2ff2cCc98971556670e287Ff0CC39DA795231ad",
729 "0x76b7E1473f0D0A87E9B4a14E2B179266802740f5",
730 "0xA7Bc965660a6EF4687CCa4F69A97563163A3C2Ef",
731 "0xB9C2b47888B9F8f7D03dC1de83F3F55E738CebD3",
732 "0xEd400162E6Dd6bD2271728FFb04176bF770De94a",
733 "0xE3E8331156700339142189B6E555DCb2c0962750",
734 "0xbf62e342Bc7706a448EdD52AE871d9C4497A53b1",
735 "0xb9d7A1A111eed75714a0AcD2dd467E872eE6B03D",
736 "0x03942919DFD0383b8c574AB8A701d89fd4bfA69D",
737 "0x0Ef4C92355D3c8c7050DFeb319790EFCcBE6fe9e",
738 "0xA6895a3cf0C60212a73B3891948ACEcF1753f25E",
739 "0x0Ed509239DB59ef3503ded3d31013C983d52803A",
740 "0xc4CE8abD123BfAFc4deFf37c7D11DeCd5c350EE4",
741 "0x4A4Bf59f7038eDcd8597004f35d7Ee24a7Bdd2d3",
742 "0x5769E8e8A2656b5ed6b6e6fa2a2bFAeaf970BB87",
743 "0xf9E15cCE181332F4F57386687c1776b66C377060",
744 "0xc98f8d4843D56a46C21171900d3eE538Cc74dbb5",
745 "0x3605965B47544Ce4302b988788B8195601AE4dEd",
746 "0xe993BDfdcAac2e65018efeE0F69A12678031c71d",
747 "0x274fDf8801385D3FAc954BCc1446Af45f5a8304c",
748 "0xBFb3f476fcD6429F4a475bA23cEFdDdd85c6b964",
749 "0x806cD16588Fe812ae740e931f95A289aFb4a4B50",
750 "0xa89488CE3bD9C25C3aF797D1bbE6CA689De79d81",
751 "0xd412f1AfAcf0Ebf3Cd324593A231Fc74CC488B12",
752 "0xd1f715b2D7951d54bc31210BbD41852D9BF98Ed1",
753 "0xf65aD707c344171F467b2ADba3d14f312219cE23",
754 "0x2971a4b242e9566dEF7bcdB7347f5E484E11919B",
755 "0x12b113D6827E07E7D426649fBd605f427da52314",
756 "0x1c6CA45171CDb9856A6C9Dba9c5F1216913C1e97",
757 "0x11cC6ee1d74963Db23294FCE1E3e0A0555779CeA",
758 "0x8Aa1C721255CDC8F895E4E4c782D86726b068667",
759 "0xA2cDC1f37510814485129aC6310b22dF04e9Bbf0",
760 "0xCf531b71d388EB3f5889F1f78E0d77f6fb109767",
761 "0xBe703e3545B2510979A0cb0C440C0Fba55c6dCB5",
762 "0x30a35886F989db39c797D8C93880180Fdd71b0c8",
763 "0x1071370D981F60c47A9Cd27ac0A61873a372cBB2",
764 "0x3515d74A11e0Cb65F0F46cB70ecf91dD1712daaa",
765 "0x50500a3c2b7b1229c6884505D00ac6Be29Aecd0C",
766 "0x9A223c2a11D4FD3585103B21B161a2B771aDA3d1",
767 "0xd7218df03AD0907e6c08E707B15d9BD14285e657",
768 "0x76CfD72eF5f93D1a44aD1F80856797fBE060c70a",
769 "0x44d093cB745944991EFF5cBa151AA6602d6f5420",
770 "0x626516DfF43bf09A71eb6fd1510E124F96ED0Cde",
771 "0x6530824632dfe099304E2DC5701cA99E6d031E08",
772 "0x57e6c423d6a7607160d6379A0c335025A14DaFC0",
773 "0x3966D4AD461Ef150E0B10163C81E79b9029E69c3",
774 "0xF608aCfd0C286E23721a3c347b2b65039f6690F1",
775 "0xbfB8FAac31A25646681936977837f7740fCd0072",
776 "0xd80aa634a623a7ED1F069a1a3A28a173061705c7",
777 "0x9122a77B36363e24e12E1E2D73F87b32926D3dF5",
778 "0x62562f0d1cD31315bCCf176049B6279B2bfc39C2",
779 "0x48aBF7A2a7119e5675059E27a7082ba7F38498b2",
780 "0xb4596983AB9A9166b29517acD634415807569e5F",
781 "0x52519D16E20BC8f5E96Da6d736963e85b2adA118",
782 "0x7663893C3dC0850EfC5391f5E5887eD723e51B83",
783 "0x5FF323a29bCC3B5b4B107e177EccEF4272959e61",
784 "0xee6e499AdDf4364D75c05D50d9344e9daA5A9AdF",
785 "0x1631b0BD31fF904aD67dD58994C6C2051CDe4E75",
786 "0xbc208e9723D44B9811C428f6A55722a26204eEF2",
787 "0xe76103a222Ee2C7Cf05B580858CEe625C4dc00E1",
788 "0xC71Bb2DBC51760f4fc2D46D84464410760971B8a",
789 "0xB4C18811e6BFe564D69E12c224FFc57351f7a7ff",
790 "0xD11DB0F5b41061A887cB7eE9c8711438844C298A",
791 "0xB931269934A3D4432c084bAAc3d0de8143199F4f",
792 "0x070037cc85C761946ec43ea2b8A2d5729908A2a1",
793 "0x2E34aa8C95Ffdbb37f14dCfBcA69291c55Ba48DE",
794 "0x052D93e8d9220787c31d6D83f87eC7dB088E998f",
795 "0x498dAC6C69b8b9ad645217050054840f1D91D029",
796 "0xE4F7D60f9d84301e1fFFd01385a585F3A11F8E89",
797 "0xEa637992f30eA06460732EDCBaCDa89355c2a107",
798 "0x4960d8Da07c27CB6Be48a79B96dD70657c57a6bF",
799 "0x7e471A003C8C9fdc8789Ded9C3dbe371d8aa0329",
800 "0xd24265Cc10eecb9e8d355CCc0dE4b11C556E74D7",
801 "0xDE59C8f7557Af779674f41CA2cA855d571018690",
802 "0x2fA8A6b3b6226d8efC9d8f6EBDc73Ca33DDcA4d8",
803 "0xe44102664c6c2024673Ff07DFe66E187Db77c65f",
804 "0x94E3f4f90a5f7CBF2cc2623e66B8583248F01022",
805 "0x0383EdBbc21D73DEd039E9C1Ff6bf56017b4CC40",
806 "0x64C3E49898B88d1E0f0d02DA23E0c00A2Cd0cA99",
807 "0xF4ccfB67b938d82B70bAb20975acFAe402E812E1",
808 "0x4f9ee5829e9852E32E7BC154D02c91D8E203e074",
809 "0xb006312eF9713463bB33D22De60444Ba95609f6B",
810 "0x7Cbe76ef69B52110DDb2e3b441C04dDb11D63248",
811 "0x70ADEEa65488F439392B869b1Df7241EF317e221",
812 "0x64C0bf8AA36Ba590477585Bc0D2BDa7970769463",
813 "0xA4cDc98593CE52d01Fe5Ca47CB3dA5320e0D7592",
814 "0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB",
815 ];
816 let root: H256 = array_bytes::hex2array_unchecked(
817 "72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53",
818 )
819 .into();
820
821 let data = addresses
822 .into_iter()
823 .map(|address| array_bytes::hex2bytes_unchecked(&address))
824 .collect::<Vec<_>>();
825
826 for l in 0..data.len() as u32 {
827 let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
829 assert_eq!(array_bytes::bytes2hex("", &proof.root), array_bytes::bytes2hex("", &root));
830 assert_eq!(proof.leaf_index, l);
831 assert_eq!(&proof.leaf, &data[l as usize]);
832
833 assert!(verify_proof::<Keccak256, _, _>(
835 &proof.root,
836 proof.proof,
837 data.len() as _,
838 proof.leaf_index,
839 &proof.leaf
840 ));
841 }
842
843 let proof = merkle_proof::<Keccak256, _, _>(data.clone(), data.len() as u32 - 1);
844
845 assert_eq!(
846 proof,
847 MerkleProof {
848 root,
849 proof: vec![
850 array_bytes::hex2array_unchecked(
851 "340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f"
852 )
853 .into(),
854 array_bytes::hex2array_unchecked(
855 "ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f"
856 )
857 .into(),
858 array_bytes::hex2array_unchecked(
859 "d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79"
860 )
861 .into(),
862 array_bytes::hex2array_unchecked(
863 "ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e"
864 )
865 .into(),
866 ],
867 number_of_leaves: data.len() as _,
868 leaf_index: data.len() as u32 - 1,
869 leaf: array_bytes::hex2array_unchecked::<_, 20>(
870 "c26B34D375533fFc4c5276282Fa5D660F3d8cbcB"
871 )
872 .to_vec(),
873 }
874 );
875 }
876
877 #[test]
878 fn proof_capacity_matches_ceil_log2() {
879 let cases = [
881 (0, 0),
882 (1, 0),
883 (2, 1),
884 (3, 2),
885 (4, 2),
886 (5, 3),
887 (7, 3),
888 (8, 3),
889 (9, 4),
890 (1 << 20, 20),
891 (u32::MAX, 32),
892 ];
893 for (n, expected) in cases {
894 assert_eq!(proof_capacity(n), expected, "n={n}");
895 }
896 }
897
898 #[test]
899 fn proof_length_never_exceeds_tree_height() {
900 for n in 1u32..=130 {
903 let data: Vec<H256> = (0..n).map(|i| H256::repeat_byte(i as u8)).collect();
904 let max = proof_capacity(n);
905 for leaf_index in 0..n {
906 let proof = merkle_proof::<Keccak256, _, _>(data.clone(), leaf_index);
907 assert!(
908 proof.proof.len() <= max,
909 "n={n}, leaf={leaf_index}: proof len {} exceeds height {max}",
910 proof.proof.len(),
911 );
912 }
913 }
914 }
915}