From b87db143c2e11d82a34f864b9c5142414c42525d Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Mon, 12 Sep 2022 13:05:00 -0700 Subject: [PATCH 01/11] add nomad primitives --- Cargo.lock | 766 ++++++- Cargo.toml | 6 +- fuzzing/Cargo.toml | 2 +- kate/Cargo.toml | 2 +- node/Cargo.toml | 2 +- pallets/dactr/Cargo.toml | 2 +- pallets/executive/Cargo.toml | 2 +- pallets/system/Cargo.toml | 2 +- pallets/system/benchmarking/Cargo.toml | 2 +- primitives/{ => avail}/Cargo.toml | 0 primitives/{ => avail}/src/asdr.rs | 0 .../src/asdr/app_unchecked_extrinsic.rs | 0 .../{ => avail}/src/asdr/data_lookup.rs | 0 primitives/{ => avail}/src/asdr/get_app_id.rs | 0 primitives/{ => avail}/src/header.rs | 4 + primitives/{ => avail}/src/kate_commitment.rs | 0 primitives/{ => avail}/src/lib.rs | 0 primitives/{ => avail}/src/traits.rs | 3 + primitives/nomad/merkle/Cargo.toml | 43 + primitives/nomad/merkle/fixtures/merkle.json | 2029 +++++++++++++++++ primitives/nomad/merkle/src/error.rs | 32 + primitives/nomad/merkle/src/lib.rs | 84 + primitives/nomad/merkle/src/light.rs | 203 ++ primitives/nomad/merkle/src/proof.rs | 58 + primitives/nomad/merkle/src/test_utils.rs | 29 + primitives/nomad/merkle/src/utils.rs | 39 + primitives/nomad/nomad-base/Cargo.toml | 55 + primitives/nomad/nomad-base/src/lib.rs | 123 + primitives/nomad/nomad-base/src/testing.rs | 32 + primitives/nomad/nomad-core/Cargo.toml | 59 + primitives/nomad/nomad-core/src/lib.rs | 23 + .../nomad/nomad-core/src/nomad_message.rs | 44 + primitives/nomad/nomad-core/src/state.rs | 16 + primitives/nomad/nomad-core/src/test_utils.rs | 51 + .../nomad/nomad-core/src/typed_message.rs | 20 + primitives/nomad/nomad-core/src/update.rs | 90 + primitives/nomad/nomad-core/src/update_v2.rs | 85 + primitives/nomad/nomad-core/src/utils.rs | 45 + primitives/nomad/signature/Cargo.toml | 69 + primitives/nomad/signature/README.md | 1 + primitives/nomad/signature/src/lib.rs | 12 + primitives/nomad/signature/src/signature.rs | 286 +++ primitives/nomad/signature/src/utils.rs | 35 + rpc/kate-rpc/Cargo.toml | 2 +- runtime/Cargo.toml | 2 +- 45 files changed, 4313 insertions(+), 47 deletions(-) rename primitives/{ => avail}/Cargo.toml (100%) rename primitives/{ => avail}/src/asdr.rs (100%) rename primitives/{ => avail}/src/asdr/app_unchecked_extrinsic.rs (100%) rename primitives/{ => avail}/src/asdr/data_lookup.rs (100%) rename primitives/{ => avail}/src/asdr/get_app_id.rs (100%) rename primitives/{ => avail}/src/header.rs (98%) rename primitives/{ => avail}/src/kate_commitment.rs (100%) rename primitives/{ => avail}/src/lib.rs (100%) rename primitives/{ => avail}/src/traits.rs (92%) create mode 100644 primitives/nomad/merkle/Cargo.toml create mode 100644 primitives/nomad/merkle/fixtures/merkle.json create mode 100644 primitives/nomad/merkle/src/error.rs create mode 100644 primitives/nomad/merkle/src/lib.rs create mode 100644 primitives/nomad/merkle/src/light.rs create mode 100644 primitives/nomad/merkle/src/proof.rs create mode 100644 primitives/nomad/merkle/src/test_utils.rs create mode 100644 primitives/nomad/merkle/src/utils.rs create mode 100644 primitives/nomad/nomad-base/Cargo.toml create mode 100644 primitives/nomad/nomad-base/src/lib.rs create mode 100644 primitives/nomad/nomad-base/src/testing.rs create mode 100644 primitives/nomad/nomad-core/Cargo.toml create mode 100644 primitives/nomad/nomad-core/src/lib.rs create mode 100644 primitives/nomad/nomad-core/src/nomad_message.rs create mode 100644 primitives/nomad/nomad-core/src/state.rs create mode 100644 primitives/nomad/nomad-core/src/test_utils.rs create mode 100644 primitives/nomad/nomad-core/src/typed_message.rs create mode 100644 primitives/nomad/nomad-core/src/update.rs create mode 100644 primitives/nomad/nomad-core/src/update_v2.rs create mode 100644 primitives/nomad/nomad-core/src/utils.rs create mode 100644 primitives/nomad/signature/Cargo.toml create mode 100644 primitives/nomad/signature/README.md create mode 100644 primitives/nomad/signature/src/lib.rs create mode 100644 primitives/nomad/signature/src/signature.rs create mode 100644 primitives/nomad/signature/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 990fd6134..f100b58aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -399,18 +399,58 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + [[package]] name = "base58" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" +[[package]] +name = "base58check" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" +dependencies = [ + "base58 0.1.0", + "sha2 0.8.2", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + [[package]] name = "bimap" version = "0.6.2" @@ -466,6 +506,16 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + [[package]] name = "bitvec" version = "0.18.5" @@ -626,8 +676,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4caf0101205582491f772d60a6fcb6bcec19963e68209cb631851eeadb01421f" dependencies = [ "bitvec 0.18.5", - "ff", - "group", + "ff 0.8.0", + "group 0.8.0", "pairing", "rand_core 0.5.1", "subtle", @@ -699,6 +749,9 @@ name = "bytes" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +dependencies = [ + "serde", +] [[package]] name = "cache-padded" @@ -885,6 +938,63 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "coins-bip32" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471b39eadc9323de375dce5eff149a5a1ebd21c67f1da34a56f87ee62191d4ea" +dependencies = [ + "bincode", + "bs58", + "coins-core", + "digest 0.9.0", + "getrandom 0.2.6", + "hmac 0.11.0", + "k256", + "lazy_static", + "serde", + "sha2 0.9.9", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f473ea37dfc9d2cb94fdde50c3d41f28c3f384b367573d66386fea38d76d466" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom 0.2.6", + "hex", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "rand 0.8.5", + "sha2 0.9.9", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257d975731955ee86fa7f348000c3fea09c262e84c70c11e994a85aa4f467a7" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32", + "blake2", + "digest 0.9.0", + "generic-array 0.14.5", + "hex", + "ripemd160", + "serde", + "serde_derive", + "sha2 0.9.9", + "sha3 0.9.1", + "thiserror", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -894,6 +1004,12 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -906,6 +1022,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + [[package]] name = "core-foundation" version = "0.9.3" @@ -1135,6 +1257,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.5", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1469,6 +1603,15 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derive-hex" version = "0.1.2" @@ -1486,7 +1629,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version 0.4.0", @@ -1519,6 +1662,7 @@ checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ "block-buffer 0.10.2", "crypto-common", + "subtle", ] [[package]] @@ -1670,13 +1814,25 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature 1.4.0", +] + [[package]] name = "ed25519" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d5c4b5e5959dc2c2b89918d8e2cc40fcdd623cef026ed09d2f0ee05199dc8e4" dependencies = [ - "signature", + "signature 1.4.0", ] [[package]] @@ -1699,6 +1855,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff 0.11.1", + "generic-array 0.14.5", + "group 0.11.0", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-as-inner" version = "0.3.4" @@ -1751,6 +1925,119 @@ dependencies = [ "libc", ] +[[package]] +name = "eth-keystore" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f65b750ac950f2f825b36d08bef4cda4112e19a7b1a68f6e2bb499413e12440" +dependencies = [ + "aes", + "ctr", + "digest 0.10.3", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.2", + "sha3 0.10.4", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "17.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.4", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types 0.11.1", + "uint", +] + +[[package]] +name = "ethers-core" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4536e70feeae231b73ac2221f1339a9a1969dea9cf1d679be26b73a36f14f4e7" +dependencies = [ + "arrayvec 0.7.2", + "bytes 1.1.0", + "chrono", + "convert_case 0.5.0", + "elliptic-curve", + "ethabi", + "generic-array 0.14.5", + "hex", + "k256", + "proc-macro2", + "rand 0.8.5", + "rlp", + "rlp-derive", + "rust_decimal", + "serde", + "serde_json", + "strum 0.24.1", + "syn", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-signers" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338efd9a6a15986fb7ed13ac7a99fd540666a2d7f475ed624d4f2ffc5ce3ec27" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "hex", + "rand 0.8.5", + "sha2 0.9.9", + "thiserror", +] + [[package]] name = "event-listener" version = "2.5.2" @@ -1807,6 +2094,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "file-per-thread-logger" version = "0.1.5" @@ -2399,11 +2696,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc11f9f5fbf1943b48ae7c2bf6846e7d827a512d1be4f23af708f5ca5d01dde1" dependencies = [ "byteorder", - "ff", + "ff 0.8.0", "rand_core 0.5.1", "subtle", ] +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff 0.11.1", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "h2" version = "0.3.13" @@ -2538,6 +2846,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", +] + [[package]] name = "hmac-drbg" version = "0.3.0" @@ -2709,6 +3026,24 @@ dependencies = [ "parity-scale-codec 2.3.1", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec 3.1.5", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + [[package]] name = "impl-serde" version = "0.3.2" @@ -2991,6 +3326,20 @@ dependencies = [ "slab", ] +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", + "sha3 0.9.1", +] + [[package]] name = "kate" version = "0.1.0" @@ -3153,6 +3502,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -3318,7 +3670,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfeead619eb5dac46e65acc78c535a60aaec803d1428cca6407c3a4fc74d698d" dependencies = [ "asynchronous-codec 0.6.0", - "base64", + "base64 0.13.0", "byteorder", "bytes 1.1.0", "fnv", @@ -3498,7 +3850,7 @@ dependencies = [ "pin-project 1.0.10", "rand 0.7.3", "salsa20", - "sha3", + "sha3 0.9.1", ] [[package]] @@ -3684,7 +4036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" dependencies = [ "arrayref", - "base64", + "base64 0.13.0", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -3929,6 +4281,27 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +[[package]] +name = "merkle" +version = "0.1.0" +dependencies = [ + "ethers-core", + "frame-support", + "lazy_static", + "parity-scale-codec 2.3.1", + "parity-util-mem", + "primitive-types 0.10.1", + "scale-info", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "thiserror-no-std", + "tiny-keccak", +] + [[package]] name = "merlin" version = "2.0.1" @@ -4088,7 +4461,7 @@ dependencies = [ "generic-array 0.14.5", "multihash-derive", "sha2 0.9.9", - "sha3", + "sha3 0.9.1", "unsigned-varint 0.5.1", ] @@ -4210,6 +4583,47 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nomad-base" +version = "0.1.0" +dependencies = [ + "ethers-signers", + "frame-support", + "nomad-core", + "once_cell", + "parity-scale-codec 2.3.1", + "parity-util-mem", + "primitive-types 0.10.1", + "scale-info", + "serde", + "signature 0.1.0", + "sp-core", + "sp-io", + "sp-std", + "tiny-keccak", +] + +[[package]] +name = "nomad-core" +version = "0.1.0" +dependencies = [ + "async-trait", + "ethers-core", + "ethers-signers", + "frame-support", + "getrandom 0.2.6", + "parity-scale-codec 2.3.1", + "parity-util-mem", + "primitive-types 0.10.1", + "scale-info", + "serde", + "signature 0.1.0", + "sp-core", + "sp-io", + "sp-std", + "tiny-keccak", +] + [[package]] name = "ntapi" version = "0.3.7" @@ -4324,9 +4738,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "oorandom" @@ -4396,8 +4810,8 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f702cdbee9e0a6272452c20dec82465bc821116598b4eeb63e9a71a69dbf7fd" dependencies = [ - "ff", - "group", + "ff 0.8.0", + "group 0.8.0", ] [[package]] @@ -5042,7 +5456,7 @@ dependencies = [ "impl-trait-for-tuples", "parity-util-mem-derive", "parking_lot", - "primitive-types", + "primitive-types 0.10.1", "smallvec", "winapi 0.3.9", ] @@ -5122,6 +5536,39 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "password-hash" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "password-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "paste" version = "1.0.7" @@ -5143,7 +5590,32 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" dependencies = [ + "base64ct", "crypto-mac 0.11.1", + "hmac 0.11.0", + "password-hash 0.2.3", + "sha2 0.9.9", +] + +[[package]] +name = "pbkdf2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.3", + "hmac 0.12.1", + "password-hash 0.4.2", + "sha2 0.10.2", ] [[package]] @@ -5275,6 +5747,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + [[package]] name = "pkg-config" version = "0.3.25" @@ -5364,12 +5847,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ "fixed-hash", - "impl-codec", + "impl-codec 0.5.1", "impl-serde", "scale-info", "uint", ] +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash", + "impl-codec 0.6.0", + "impl-rlp", + "impl-serde", + "uint", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -5415,11 +5911,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -5823,6 +6319,17 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ring" version = "0.16.20" @@ -5838,6 +6345,38 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "rlp" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" +dependencies = [ + "bytes 1.1.0", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rocksdb" version = "0.17.0" @@ -5885,6 +6424,17 @@ dependencies = [ "rustc_version 0.4.0", ] +[[package]] +name = "rust_decimal" +version = "1.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" +dependencies = [ + "arrayvec 0.7.2", + "num-traits", + "serde", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -5936,7 +6486,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", + "base64 0.13.0", "log", "ring", "sct", @@ -5955,6 +6505,12 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + [[package]] name = "rusty-fork" version = "0.3.0" @@ -7017,6 +7573,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scrypt" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e73d6d7c6311ebdbd9184ad6c4447b2f36337e327bda107d3ba9e3c374f9d325" +dependencies = [ + "hmac 0.12.1", + "password-hash 0.3.2", + "pbkdf2 0.10.1", + "salsa20", + "sha2 0.10.2", +] + [[package]] name = "sct" version = "0.6.1" @@ -7027,6 +7596,19 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array 0.14.5", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -7222,6 +7804,16 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha3" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaedf34ed289ea47c2b741bb72e5357a209512d67bcd4bda44359e5bf0470f56" +dependencies = [ + "digest 0.10.3", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -7258,9 +7850,41 @@ dependencies = [ [[package]] name = "signature" -version = "1.5.0" +version = "0.1.0" +dependencies = [ + "arrayvec 0.7.2", + "byte-slice-cast", + "elliptic-curve", + "ethabi", + "ethers-core", + "frame-support", + "generic-array 0.14.5", + "hex", + "k256", + "once_cell", + "parity-scale-codec 2.3.1", + "parity-util-mem", + "primitive-types 0.10.1", + "rlp", + "rlp-derive", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std", + "thiserror-no-std", + "tiny-keccak", +] + +[[package]] +name = "signature" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] [[package]] name = "simba" @@ -7337,7 +7961,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64", + "base64 0.13.0", "bytes 1.1.0", "flate2", "futures 0.3.21", @@ -7548,7 +8172,7 @@ name = "sp-core" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.13#afb74de23dfe2994e7ce38c0870efb9734e966f7" dependencies = [ - "base58", + "base58 0.2.0", "bitflags", "blake2-rfc", "byteorder", @@ -7567,7 +8191,7 @@ dependencies = [ "parity-scale-codec 2.3.1", "parity-util-mem", "parking_lot", - "primitive-types", + "primitive-types 0.10.1", "rand 0.7.3", "regex", "scale-info", @@ -7709,7 +8333,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum", + "strum 0.22.0", ] [[package]] @@ -7822,7 +8446,7 @@ source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.1 dependencies = [ "impl-trait-for-tuples", "parity-scale-codec 2.3.1", - "primitive-types", + "primitive-types 0.10.1", "sp-externalities", "sp-runtime-interface-proc-macro", "sp-std", @@ -8044,6 +8668,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" version = "1.17.0" @@ -8126,7 +8760,16 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" dependencies = [ - "strum_macros", + "strum_macros 0.22.0", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", ] [[package]] @@ -8141,6 +8784,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "substrate-bip39" version = "0.4.4" @@ -8223,13 +8879,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.91" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -8309,24 +8965,44 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl-no-std" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "thiserror-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" +dependencies = [ + "thiserror-impl-no-std", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -8706,6 +9382,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -8729,9 +9411,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "universal-hash" @@ -8802,6 +9484,16 @@ dependencies = [ "percent-encoding 2.1.0", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.6", + "serde", +] + [[package]] name = "valuable" version = "0.1.0" @@ -9057,7 +9749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36147930a4995137dc096e5b17a573b446799be2bbaea433e821ce6a80abe2c5" dependencies = [ "anyhow", - "base64", + "base64 0.13.0", "bincode", "directories-next", "file-per-thread-logger", diff --git a/Cargo.toml b/Cargo.toml index 581cb28fe..839af0a54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,11 @@ members = [ "kate/recovery", "kate/proof", "fuzzing", - "primitives", + "primitives/avail", + "primitives/nomad/merkle", + "primitives/nomad/signature", + "primitives/nomad/nomad-core", + "primitives/nomad/nomad-base", "pallets/executive", "pallets/system", "pallets/dactr", diff --git a/fuzzing/Cargo.toml b/fuzzing/Cargo.toml index e7906b367..f12243444 100644 --- a/fuzzing/Cargo.toml +++ b/fuzzing/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" afl = "*" kate-recovery = {path = "../kate/recovery"} kate = {path = "../kate"} -da-primitives = { path = "../primitives", default-features = false } +da-primitives = { path = "../primitives/avail", default-features = false } hex-literal = "0.3.1" [[bin]] diff --git a/kate/Cargo.toml b/kate/Cargo.toml index 724be04ae..cf81364e9 100644 --- a/kate/Cargo.toml +++ b/kate/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -da-primitives = { path = "../primitives", default-features = false } +da-primitives = { path = "../primitives/avail", default-features = false } # Others dusk-plonk = { git = "https://github.com/maticnetwork/plonk.git", branch = "v0.8.2-polygon-5", optional = true } diff --git a/node/Cargo.toml b/node/Cargo.toml index e10958627..0b2cd5b2a 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -18,7 +18,7 @@ name = "data-avail" [dependencies] # Internals -da-primitives= { path = "../primitives" } +da-primitives= { path = "../primitives/avail" } da-runtime = { path = "../runtime" } da-control = { path = "../pallets/dactr" } kate = { path = "../kate" } diff --git a/pallets/dactr/Cargo.toml b/pallets/dactr/Cargo.toml index 83036db97..54da13c48 100644 --- a/pallets/dactr/Cargo.toml +++ b/pallets/dactr/Cargo.toml @@ -12,7 +12,7 @@ description = "Data Avail Control Module" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -da-primitives = { path = "../../primitives", default-features = false } +da-primitives = { path = "../../primitives/avail", default-features = false } kate = { path = "../../kate", default-features = false } # Substrate diff --git a/pallets/executive/Cargo.toml b/pallets/executive/Cargo.toml index 3641504ac..d182a6a56 100644 --- a/pallets/executive/Cargo.toml +++ b/pallets/executive/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -da-primitives = { path = "../../primitives", default-features = false } +da-primitives = { path = "../../primitives/avail", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", diff --git a/pallets/system/Cargo.toml b/pallets/system/Cargo.toml index c41e0b213..1d36f9526 100644 --- a/pallets/system/Cargo.toml +++ b/pallets/system/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] kate = { path = "../../kate", default-features = false } -da-primitives = { path = "../../primitives", default-features = false } +da-primitives = { path = "../../primitives/avail", default-features = false } # Other impl-trait-for-tuples = "0.2.1" diff --git a/pallets/system/benchmarking/Cargo.toml b/pallets/system/benchmarking/Cargo.toml index c4b9f7da2..38d060ec4 100644 --- a/pallets/system/benchmarking/Cargo.toml +++ b/pallets/system/benchmarking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -da-primitives = { path = "../../../primitives", default-features = false } +da-primitives = { path = "../../../primitives/avail", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false } diff --git a/primitives/Cargo.toml b/primitives/avail/Cargo.toml similarity index 100% rename from primitives/Cargo.toml rename to primitives/avail/Cargo.toml diff --git a/primitives/src/asdr.rs b/primitives/avail/src/asdr.rs similarity index 100% rename from primitives/src/asdr.rs rename to primitives/avail/src/asdr.rs diff --git a/primitives/src/asdr/app_unchecked_extrinsic.rs b/primitives/avail/src/asdr/app_unchecked_extrinsic.rs similarity index 100% rename from primitives/src/asdr/app_unchecked_extrinsic.rs rename to primitives/avail/src/asdr/app_unchecked_extrinsic.rs diff --git a/primitives/src/asdr/data_lookup.rs b/primitives/avail/src/asdr/data_lookup.rs similarity index 100% rename from primitives/src/asdr/data_lookup.rs rename to primitives/avail/src/asdr/data_lookup.rs diff --git a/primitives/src/asdr/get_app_id.rs b/primitives/avail/src/asdr/get_app_id.rs similarity index 100% rename from primitives/src/asdr/get_app_id.rs rename to primitives/avail/src/asdr/get_app_id.rs diff --git a/primitives/src/header.rs b/primitives/avail/src/header.rs similarity index 98% rename from primitives/src/header.rs rename to primitives/avail/src/header.rs index a379d1040..fc8984600 100644 --- a/primitives/src/header.rs +++ b/primitives/avail/src/header.rs @@ -276,6 +276,10 @@ where fn set_extrinsics_root(&mut self, root: Self::Root) { self.extrinsics_root = root; } + fn data_root(&self) -> &[u8; 32] { &self.extrinsics_root.data_root } + + fn set_data_root(&mut self, data_root: [u8; 32]) { self.extrinsics_root.data_root = data_root; } + fn data_lookup(&self) -> &DataLookup { &self.app_data_lookup } /// Creates new header. diff --git a/primitives/src/kate_commitment.rs b/primitives/avail/src/kate_commitment.rs similarity index 100% rename from primitives/src/kate_commitment.rs rename to primitives/avail/src/kate_commitment.rs diff --git a/primitives/src/lib.rs b/primitives/avail/src/lib.rs similarity index 100% rename from primitives/src/lib.rs rename to primitives/avail/src/lib.rs diff --git a/primitives/src/traits.rs b/primitives/avail/src/traits.rs similarity index 92% rename from primitives/src/traits.rs rename to primitives/avail/src/traits.rs index 8ba79a858..92bc0c3f5 100644 --- a/primitives/src/traits.rs +++ b/primitives/avail/src/traits.rs @@ -36,6 +36,9 @@ pub trait ExtendedHeader { fn extrinsics_root(&self) -> &Self::Root; fn set_extrinsics_root(&mut self, root: Self::Root); + fn data_root(&self) -> &[u8; 32]; + fn set_data_root(&mut self, root: [u8; 32]); + fn data_lookup(&self) -> &DataLookup; /// Creates new header. diff --git a/primitives/nomad/merkle/Cargo.toml b/primitives/nomad/merkle/Cargo.toml new file mode 100644 index 000000000..9ac1b3e49 --- /dev/null +++ b/primitives/nomad/merkle/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "merkle" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Substrate +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false } +sp-core = { version = "4.0.0-dev", default-features = false } +sp-io = { version = "4.0.0-dev", default-features = false } +sp-runtime = { version = "4.0.0-dev", default-features = false } +frame-support = { version = "4.0.0-dev", default-features = false } +parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } + +primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info", "codec"] } +tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } +thiserror-no-std = "2.0.2" + +[dev-dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = { version = "1.0" } +ethers-core = "0.13.0" + +[dependencies.serde] +version = "1.0" +default-features = false +optional = true +features = ["derive"] + +[features] +default = ["std"] +std = [ + "serde", + "primitive-types/serde", + "codec/std", + "scale-info/std", + "frame-support/std", +] \ No newline at end of file diff --git a/primitives/nomad/merkle/fixtures/merkle.json b/primitives/nomad/merkle/fixtures/merkle.json new file mode 100644 index 000000000..afb59f1dc --- /dev/null +++ b/primitives/nomad/merkle/fixtures/merkle.json @@ -0,0 +1,2029 @@ +[ + { + "testName": "three leaves", + "expectedRoot": "0x18f2f1646fee335a1eaf5191a8ce58ea772080057d0fda687df59c45e47e6f68", + "leaves": [ + "one", + "two", + "three" + ], + "proofs": [ + { + "leaf": "0xf0fe7c99ef23ace1835385e83dd61c9ecb6192d6514fcc13356ef912788eaa8a", + "index": 0, + "path": [ + "0x65ad6b7c39c687dad3edc05bec09300b742363f5c1f42db586bdce40c9fc5eef", + "0xe9884debea0619a2ce25ba3bbe6a4438a42bc11b2308f62c65ed43be0b43d445", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x65ad6b7c39c687dad3edc05bec09300b742363f5c1f42db586bdce40c9fc5eef", + "index": 1, + "path": [ + "0xf0fe7c99ef23ace1835385e83dd61c9ecb6192d6514fcc13356ef912788eaa8a", + "0xe9884debea0619a2ce25ba3bbe6a4438a42bc11b2308f62c65ed43be0b43d445", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x769dbf057c1b1544b7b4a9a4f98893cad73080764ad63ee83344312494dc296e", + "index": 2, + "path": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x606fc91d919e5a5b5b0ce2a1b2f6d33355b39558b5a12a4b14c3a381b18769a2", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + } + ] + }, + { + "testName": "one leaf", + "expectedRoot": "0x54fea87823728b754368018753f79a24e5f5cacee26c8785f3d33aabfd03372e", + "leaves": [ + "one" + ], + "proofs": [ + { + "leaf": "0xf0fe7c99ef23ace1835385e83dd61c9ecb6192d6514fcc13356ef912788eaa8a", + "index": 0, + "path": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + } + ] + }, + { + "testName": "no leaves", + "expectedRoot": "0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757", + "leaves": [], + "proofs": [] + }, + { + "testName": "forty-two leaves", + "expectedRoot": "0x274d610098d8f109587e97c908cf549d129a14f5bad7eb10d36a427da97be6fc", + "leaves": [ + "bacon", + "eye", + "we", + "ghost", + "listen", + "corn", + "blonde", + "gutter", + "sanctuary", + "seat", + "generate", + "twist", + "waterfall", + "monster", + "elbow", + "flash", + "arrow", + "moment", + "cheat", + "unity", + "steak", + "shelter", + "camera", + "album", + "bread", + "tease", + "sentence", + "tribe", + "miserable", + "ridge", + "guerrilla", + "inhabitant", + "suspicion", + "mosque", + "printer", + "land", + "reliable", + "circle", + "first-hand", + "time", + "content", + "management" + ], + "proofs": [ + { + "leaf": "0xdedc5b0226dc6135af110369edd66b863f13c89043d4f68b914be1cefe27304e", + "index": 0, + "path": [ + "0x4f4fa1fc880f5f6622bd953386092771d488568327e40eaa09c403e1e4529eac", + "0x66677e36ec586995e5e91cc3bc3ff07208c03b59f3b4058dc56e608dcabe20c5", + "0xa19e6312073514ab346a7db383ab9ca167f1b9d0eb6dc76225eeb1cac766630f", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x4f4fa1fc880f5f6622bd953386092771d488568327e40eaa09c403e1e4529eac", + "index": 1, + "path": [ + "0xdedc5b0226dc6135af110369edd66b863f13c89043d4f68b914be1cefe27304e", + "0x66677e36ec586995e5e91cc3bc3ff07208c03b59f3b4058dc56e608dcabe20c5", + "0xa19e6312073514ab346a7db383ab9ca167f1b9d0eb6dc76225eeb1cac766630f", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x7003a5b06332d5f75cdf9474ccf863a7986f2eebf8fb54122011dfa4f5a0ec1f", + "index": 2, + "path": [ + "0xdb07d7a5fdaaf861f5ae3a145081c53fb6b111bffab064e201c3682b3f254fab", + "0xafe54c4a88d8b9e4707a28576e41d0be20418ab90b10654ebfd00aecd2bad592", + "0xa19e6312073514ab346a7db383ab9ca167f1b9d0eb6dc76225eeb1cac766630f", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xdb07d7a5fdaaf861f5ae3a145081c53fb6b111bffab064e201c3682b3f254fab", + "index": 3, + "path": [ + "0x7003a5b06332d5f75cdf9474ccf863a7986f2eebf8fb54122011dfa4f5a0ec1f", + "0xafe54c4a88d8b9e4707a28576e41d0be20418ab90b10654ebfd00aecd2bad592", + "0xa19e6312073514ab346a7db383ab9ca167f1b9d0eb6dc76225eeb1cac766630f", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xd9fa9b21a8500576003cc17f6f715898735b4affe6021bba300fd88b6665e70f", + "index": 4, + "path": [ + "0x745df104209724b953eadc3bdcdce16c87be927a33f6b61a1eabea980983111d", + "0x8e6af6a7c964ca809ed0fd77c7261eed5f23baf9bfe8c3aa98cb84b0a21c5190", + "0x97748c9f3b4fe02bfbca5b7752b04b6f77fc3f0753ad711b5cff568104d31a0c", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x745df104209724b953eadc3bdcdce16c87be927a33f6b61a1eabea980983111d", + "index": 5, + "path": [ + "0xd9fa9b21a8500576003cc17f6f715898735b4affe6021bba300fd88b6665e70f", + "0x8e6af6a7c964ca809ed0fd77c7261eed5f23baf9bfe8c3aa98cb84b0a21c5190", + "0x97748c9f3b4fe02bfbca5b7752b04b6f77fc3f0753ad711b5cff568104d31a0c", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x3c508ba7eb05bc907dc43e906bd5998745a94c400ba840e3a2252a1fe0493da2", + "index": 6, + "path": [ + "0x473776a7204dbaaab3e5689b20893261ab524105fe1b8f04e325e23ce33163d9", + "0xd985746e1f983a7d84824d0bc12f764fc0cfeec2850882a6dcb8b87e0049eee9", + "0x97748c9f3b4fe02bfbca5b7752b04b6f77fc3f0753ad711b5cff568104d31a0c", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x473776a7204dbaaab3e5689b20893261ab524105fe1b8f04e325e23ce33163d9", + "index": 7, + "path": [ + "0x3c508ba7eb05bc907dc43e906bd5998745a94c400ba840e3a2252a1fe0493da2", + "0xd985746e1f983a7d84824d0bc12f764fc0cfeec2850882a6dcb8b87e0049eee9", + "0x97748c9f3b4fe02bfbca5b7752b04b6f77fc3f0753ad711b5cff568104d31a0c", + "0x0bf20de5643721f47c8833fd9f81ed5b4e38b051a8fc8017c1540bbb91b32638", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xc3be211a46aaf5876c32021a85edeff36cce1c0e61a48bc93b3e71b9e2f55b17", + "index": 8, + "path": [ + "0xb281dd16a96ca77a323e291058930e46428f4931fb3aec25d07b1574584f731c", + "0xd4ae409d561eaa3eb0d4cd034a63bf37f4ac7b6d722ee496064a2bb70644ce44", + "0xc6e696f0f313b67ef05f0afa77826f5373e7fe6d769bd42b8c94ea27e640728b", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xb281dd16a96ca77a323e291058930e46428f4931fb3aec25d07b1574584f731c", + "index": 9, + "path": [ + "0xc3be211a46aaf5876c32021a85edeff36cce1c0e61a48bc93b3e71b9e2f55b17", + "0xd4ae409d561eaa3eb0d4cd034a63bf37f4ac7b6d722ee496064a2bb70644ce44", + "0xc6e696f0f313b67ef05f0afa77826f5373e7fe6d769bd42b8c94ea27e640728b", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xcae382a2f3f639f6e833ae37e4db2603b617e74827f8d819f9d64bad9d90b9b1", + "index": 10, + "path": [ + "0x38c0d391c04c3bdd439ef968d599c65976150a72b1655d7d6650cbe5844a2502", + "0xca9b27d05fc15b94d68498e756f213b5f75393f2a26c686c24aae75227e0dcc6", + "0xc6e696f0f313b67ef05f0afa77826f5373e7fe6d769bd42b8c94ea27e640728b", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x38c0d391c04c3bdd439ef968d599c65976150a72b1655d7d6650cbe5844a2502", + "index": 11, + "path": [ + "0xcae382a2f3f639f6e833ae37e4db2603b617e74827f8d819f9d64bad9d90b9b1", + "0xca9b27d05fc15b94d68498e756f213b5f75393f2a26c686c24aae75227e0dcc6", + "0xc6e696f0f313b67ef05f0afa77826f5373e7fe6d769bd42b8c94ea27e640728b", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x5573d8dcf04fd96cfe496f0bbe58ae4c97b431577261107ad0970cb802548e6b", + "index": 12, + "path": [ + "0x76c94951c7a0535e1759714f1cf568a6b17327c115b31b24cc90fae4fc69ea9c", + "0x0298e56ac1989266f4a3137545bd1a97511f40530e6fa4e21fa951b324bad2d1", + "0x9836a5d16bebd9d88a110dd88207f1ba4bd9fa919cb59d0bc0c27a3c91c3611f", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x76c94951c7a0535e1759714f1cf568a6b17327c115b31b24cc90fae4fc69ea9c", + "index": 13, + "path": [ + "0x5573d8dcf04fd96cfe496f0bbe58ae4c97b431577261107ad0970cb802548e6b", + "0x0298e56ac1989266f4a3137545bd1a97511f40530e6fa4e21fa951b324bad2d1", + "0x9836a5d16bebd9d88a110dd88207f1ba4bd9fa919cb59d0bc0c27a3c91c3611f", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xb840bbb177fc5ba12f4c6d4c9af5077105d6c933b507edfc7db36c8a192913e1", + "index": 14, + "path": [ + "0xf65ec5e6611c7426cac9f7798fe934545c9c6f861b6ec87e07502fc2a5c6a43b", + "0xacede158b8b16bcfd5d3fd4e0547d1a4d3906537b9e505f2f13c8bb50b35b576", + "0x9836a5d16bebd9d88a110dd88207f1ba4bd9fa919cb59d0bc0c27a3c91c3611f", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xf65ec5e6611c7426cac9f7798fe934545c9c6f861b6ec87e07502fc2a5c6a43b", + "index": 15, + "path": [ + "0xb840bbb177fc5ba12f4c6d4c9af5077105d6c933b507edfc7db36c8a192913e1", + "0xacede158b8b16bcfd5d3fd4e0547d1a4d3906537b9e505f2f13c8bb50b35b576", + "0x9836a5d16bebd9d88a110dd88207f1ba4bd9fa919cb59d0bc0c27a3c91c3611f", + "0x6841d65094f6e26c290c0bf0d84270c7dbba56c9124126094daf5404650bb1b9", + "0xe3e71a410d357ee0708b0764646554ec888e950e4440cf0f138d2279c647bf59", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xa14e758134deb96c68f1ea4190d27ac4f14cd77b4bb44dc1757c35cad91fd249", + "index": 16, + "path": [ + "0xe70096bebc510a5a3b07b77cbe0444576da2f1c580dc143b1ccdc399095952c9", + "0x1ca9d77bfa38c6054c5cf7995458e00612f28e18bd93d4892f513e654301a0ed", + "0x1b9795e811e59c10161ebc3a6e419fbc9d02621575bdbe66fc5840202f4caf07", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xe70096bebc510a5a3b07b77cbe0444576da2f1c580dc143b1ccdc399095952c9", + "index": 17, + "path": [ + "0xa14e758134deb96c68f1ea4190d27ac4f14cd77b4bb44dc1757c35cad91fd249", + "0x1ca9d77bfa38c6054c5cf7995458e00612f28e18bd93d4892f513e654301a0ed", + "0x1b9795e811e59c10161ebc3a6e419fbc9d02621575bdbe66fc5840202f4caf07", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x668e924309f236219283c0f16640d294edf013d7bb4953531ff7bef8780b03da", + "index": 18, + "path": [ + "0xf2a7d3c8fab1a3bc703b08b5ce78ab8ebfd2b38336d70b39d6c55e6d796bfc7f", + "0xd785b494114d63896c3ea806462858f7172f356e5f02b8131ad9020da38f2b34", + "0x1b9795e811e59c10161ebc3a6e419fbc9d02621575bdbe66fc5840202f4caf07", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xf2a7d3c8fab1a3bc703b08b5ce78ab8ebfd2b38336d70b39d6c55e6d796bfc7f", + "index": 19, + "path": [ + "0x668e924309f236219283c0f16640d294edf013d7bb4953531ff7bef8780b03da", + "0xd785b494114d63896c3ea806462858f7172f356e5f02b8131ad9020da38f2b34", + "0x1b9795e811e59c10161ebc3a6e419fbc9d02621575bdbe66fc5840202f4caf07", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xca69fd669b297fe4cc27bfb7229389d8465a82217c373bd1f6b604d23dc75541", + "index": 20, + "path": [ + "0x5715c8e3de41f125c3006466f6ef1a610467ed45d89ac848fab504adbb3e868a", + "0xf4f6e397b08163292b827532b1577aa0f843ef48b25aa1aa6e96a0ecbb3f0534", + "0xea830ec90e2b4c4eec5a704c2fbf196270fbb0149e9025c43151f499dceda93c", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x5715c8e3de41f125c3006466f6ef1a610467ed45d89ac848fab504adbb3e868a", + "index": 21, + "path": [ + "0xca69fd669b297fe4cc27bfb7229389d8465a82217c373bd1f6b604d23dc75541", + "0xf4f6e397b08163292b827532b1577aa0f843ef48b25aa1aa6e96a0ecbb3f0534", + "0xea830ec90e2b4c4eec5a704c2fbf196270fbb0149e9025c43151f499dceda93c", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x31d1564a1b6b8dd1c5cd4036878b85c58efbbd65230f4076cd72cea24a98f154", + "index": 22, + "path": [ + "0x30b25cba6ec910fe7a0b4b70fe89e7bf67d1315d8119575b2811dd18e7eb3de2", + "0x4bb1f84869a082ff32090743d10afdd86db162a5a9f3f57367070261aa83631c", + "0xea830ec90e2b4c4eec5a704c2fbf196270fbb0149e9025c43151f499dceda93c", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x30b25cba6ec910fe7a0b4b70fe89e7bf67d1315d8119575b2811dd18e7eb3de2", + "index": 23, + "path": [ + "0x31d1564a1b6b8dd1c5cd4036878b85c58efbbd65230f4076cd72cea24a98f154", + "0x4bb1f84869a082ff32090743d10afdd86db162a5a9f3f57367070261aa83631c", + "0xea830ec90e2b4c4eec5a704c2fbf196270fbb0149e9025c43151f499dceda93c", + "0xa9746be9b9a03c397661e5f88a5ea0f3750eb25936f56da836758b720fa4cb48", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x1621364c11a2ca32daef709e72728bc398c1c9fca44a613b478378d431d68718", + "index": 24, + "path": [ + "0xc1093dcc4522764deb9b3c739183dee9ad341f34659da169f67c5f5ffd78ca19", + "0xd3589bcbd40fc75989260def3c87d37f007ae533238fe81cac92eb809af55a3c", + "0x26b17a6513d3c3f33be0e7440da0fcfdaa33b6bb69cbd2019503dcd06378d240", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xc1093dcc4522764deb9b3c739183dee9ad341f34659da169f67c5f5ffd78ca19", + "index": 25, + "path": [ + "0x1621364c11a2ca32daef709e72728bc398c1c9fca44a613b478378d431d68718", + "0xd3589bcbd40fc75989260def3c87d37f007ae533238fe81cac92eb809af55a3c", + "0x26b17a6513d3c3f33be0e7440da0fcfdaa33b6bb69cbd2019503dcd06378d240", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xca0cb7165fa77f59914e8df8d8b18c9f600dc1b27d1e92d39c45d13d813853c5", + "index": 26, + "path": [ + "0xec77244f0cc53d209a29424d4ba057b2bcc00b8d98d60843df7a3ed255613386", + "0x49985b3dfc2df830e274f4644bf418fe4e3d8010d2dd94f91123463d50213d99", + "0x26b17a6513d3c3f33be0e7440da0fcfdaa33b6bb69cbd2019503dcd06378d240", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xec77244f0cc53d209a29424d4ba057b2bcc00b8d98d60843df7a3ed255613386", + "index": 27, + "path": [ + "0xca0cb7165fa77f59914e8df8d8b18c9f600dc1b27d1e92d39c45d13d813853c5", + "0x49985b3dfc2df830e274f4644bf418fe4e3d8010d2dd94f91123463d50213d99", + "0x26b17a6513d3c3f33be0e7440da0fcfdaa33b6bb69cbd2019503dcd06378d240", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xc027e6fda36b1fe17d72fb8463da7835931991aa0a687d09383358188dc94aaa", + "index": 28, + "path": [ + "0x1e308c515825785648d1f880fb1153b70efc0c7041c4e4c1e92dd4e92f4d45ea", + "0x6b6d1518efc8be5b8601c7f27027ef9e0be813ee6db267d9cf7d0b0dd1899688", + "0xb8ccc25b33d396a0c5708f0cb13181d2618a6cc95dc538ef7cae850eaaea10ea", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x1e308c515825785648d1f880fb1153b70efc0c7041c4e4c1e92dd4e92f4d45ea", + "index": 29, + "path": [ + "0xc027e6fda36b1fe17d72fb8463da7835931991aa0a687d09383358188dc94aaa", + "0x6b6d1518efc8be5b8601c7f27027ef9e0be813ee6db267d9cf7d0b0dd1899688", + "0xb8ccc25b33d396a0c5708f0cb13181d2618a6cc95dc538ef7cae850eaaea10ea", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x75090a35989bed9e15c77acafd73ea8b6dd56cccf75160f79e80545c7d6fe9a1", + "index": 30, + "path": [ + "0x10546cdf15b1dbc40610fd6634d4e20e160d32aa2b499180e2531f9e4dff5f2b", + "0xf723df57b49cec812e5c7fbea7834a70982305eb81a407fb830a5189c50f3f3d", + "0xb8ccc25b33d396a0c5708f0cb13181d2618a6cc95dc538ef7cae850eaaea10ea", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x10546cdf15b1dbc40610fd6634d4e20e160d32aa2b499180e2531f9e4dff5f2b", + "index": 31, + "path": [ + "0x75090a35989bed9e15c77acafd73ea8b6dd56cccf75160f79e80545c7d6fe9a1", + "0xf723df57b49cec812e5c7fbea7834a70982305eb81a407fb830a5189c50f3f3d", + "0xb8ccc25b33d396a0c5708f0cb13181d2618a6cc95dc538ef7cae850eaaea10ea", + "0xd2c18eb014793f8344a112a2cbee465e788a9dc14ce89389b5d9c265ec6d416c", + "0x6f197b0602b9d16dbb069ca4dcf94a825347a35061cb30a6e044790722a3d754", + "0xc9baf9cda8eaf9b9a3b456dd0e6108cf9ccf2e4a150493365a62da49fee0426d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x15a0acea87ff0a9f0a28637acefa1caba9fdb66598701d6ea0666045549cb62f", + "index": 32, + "path": [ + "0x62cef892da1c8a3b6b222a5fc54a7e15588f500a5c39c15da38bb5192e1869af", + "0xe29484e6612551bf20faad9fba9d3687a1a0b59bc37313643b3d55ee187a74e6", + "0x5e623385224fae9d4efff4b86a3193c0b823e39a472614689fcc54b173d1e498", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x62cef892da1c8a3b6b222a5fc54a7e15588f500a5c39c15da38bb5192e1869af", + "index": 33, + "path": [ + "0x15a0acea87ff0a9f0a28637acefa1caba9fdb66598701d6ea0666045549cb62f", + "0xe29484e6612551bf20faad9fba9d3687a1a0b59bc37313643b3d55ee187a74e6", + "0x5e623385224fae9d4efff4b86a3193c0b823e39a472614689fcc54b173d1e498", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xd8e15a4aa45e47de08dc0d5a1b88a4567c8bb793de2b6309a924b34f21594400", + "index": 34, + "path": [ + "0x880f289aab63ef908117bb8f9b70156cc0a9bb4e527e504fd6a479aca7c03739", + "0x4812b6b9890e0c2d80fd365ac38a0bfd30c9ba5ab8b28396fa7295c5f7f9cc09", + "0x5e623385224fae9d4efff4b86a3193c0b823e39a472614689fcc54b173d1e498", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x880f289aab63ef908117bb8f9b70156cc0a9bb4e527e504fd6a479aca7c03739", + "index": 35, + "path": [ + "0xd8e15a4aa45e47de08dc0d5a1b88a4567c8bb793de2b6309a924b34f21594400", + "0x4812b6b9890e0c2d80fd365ac38a0bfd30c9ba5ab8b28396fa7295c5f7f9cc09", + "0x5e623385224fae9d4efff4b86a3193c0b823e39a472614689fcc54b173d1e498", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xaec1732926c6969efbb2e0bf2d6fc80bfe78e5f1dc1533b800acbd293a339f71", + "index": 36, + "path": [ + "0xdbbce7f4ed1905678a14232500d05429280e9e3902815e6a595a45643129c09b", + "0xcb28c96b9b0f8b8bde8916aa45bebf368883a3fb4f6638710cc3f61d8b1e185b", + "0x4226792eeb5d994cb82a53b3017f502a70efc87f12ce215824b5826be31ef7f1", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xdbbce7f4ed1905678a14232500d05429280e9e3902815e6a595a45643129c09b", + "index": 37, + "path": [ + "0xaec1732926c6969efbb2e0bf2d6fc80bfe78e5f1dc1533b800acbd293a339f71", + "0xcb28c96b9b0f8b8bde8916aa45bebf368883a3fb4f6638710cc3f61d8b1e185b", + "0x4226792eeb5d994cb82a53b3017f502a70efc87f12ce215824b5826be31ef7f1", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x9b11dd7ebcfce9fb6e57c39abe4657abc4ac1f894ffb231acc1d4b141324852c", + "index": 38, + "path": [ + "0xe536cf6c7b89b6d158f7081b541cd33369510425a367643eb90e091e6b6e430d", + "0x8f4bcde10bb01adc55bd8f857c43c14fa5576a8720f5bf5ff517f9b05d9a7580", + "0x4226792eeb5d994cb82a53b3017f502a70efc87f12ce215824b5826be31ef7f1", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xe536cf6c7b89b6d158f7081b541cd33369510425a367643eb90e091e6b6e430d", + "index": 39, + "path": [ + "0x9b11dd7ebcfce9fb6e57c39abe4657abc4ac1f894ffb231acc1d4b141324852c", + "0x8f4bcde10bb01adc55bd8f857c43c14fa5576a8720f5bf5ff517f9b05d9a7580", + "0x4226792eeb5d994cb82a53b3017f502a70efc87f12ce215824b5826be31ef7f1", + "0xfd53f69e35c997752fbf656b13f1cf48911a7d219d29bedd55b2687025ffacbf", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x0f4018446a76e502f3ebed4e1a68dbe7c802d148ee512dee783de380c317d0d8", + "index": 40, + "path": [ + "0x28346050f1a67ddd3f6f2f7bc5e25fd013f5c8862214a82223fb1dd5715900e4", + "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", + "0x321207516f2beb911791d1a42a49dbf554f4aa7b7472562545d39e2b959be65d", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x28346050f1a67ddd3f6f2f7bc5e25fd013f5c8862214a82223fb1dd5715900e4", + "index": 41, + "path": [ + "0x0f4018446a76e502f3ebed4e1a68dbe7c802d148ee512dee783de380c317d0d8", + "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", + "0x321207516f2beb911791d1a42a49dbf554f4aa7b7472562545d39e2b959be65d", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0xb6f125e6b2977262366343bbabcbbc6a9284533e85f4caa7140e22f2bd5ab139", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + } + ] + }, + { + "testName": "containing empty leaf", + "expectedRoot": "0x1841827275d59b7515da81fb121637567b70ebd8b38ec5aadb51f4300976cba1", + "leaves": [ + "anna", + "james", + "", + "luke", + "erin" + ], + "proofs": [ + { + "leaf": "0x8bffab2351d4f65868fcdbb6d31e19d67f61d10c49b1bcc90d60fed54d9ec259", + "index": 0, + "path": [ + "0xe1e277208109c76f11aadfd43d8945f7c78a32da28df09687378435425c7a636", + "0x1fb86381cdfbd54d7ceee326730da96d69acf815c35b6ab3b2cf8c2a5f3f74a4", + "0xf9735da6e2c0e7f08a672602e23a4b3d899b12756e9e6ea171f19fa8f93ec4d7", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0xe1e277208109c76f11aadfd43d8945f7c78a32da28df09687378435425c7a636", + "index": 1, + "path": [ + "0x8bffab2351d4f65868fcdbb6d31e19d67f61d10c49b1bcc90d60fed54d9ec259", + "0x1fb86381cdfbd54d7ceee326730da96d69acf815c35b6ab3b2cf8c2a5f3f74a4", + "0xf9735da6e2c0e7f08a672602e23a4b3d899b12756e9e6ea171f19fa8f93ec4d7", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x5f35dce98ba4fba25530a026ed80b2cecdaa31091ba4958b99b52ea1d068adad", + "index": 2, + "path": [ + "0x15881b991602c46d60dc4e4b7cb3c7d6df9fa9cfc6d93a749ac9428a8ad9f0d7", + "0x15baffb1b0f3a33541686a8c657aa2b592994a26c053479b3aedfdd303473675", + "0xf9735da6e2c0e7f08a672602e23a4b3d899b12756e9e6ea171f19fa8f93ec4d7", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x15881b991602c46d60dc4e4b7cb3c7d6df9fa9cfc6d93a749ac9428a8ad9f0d7", + "index": 3, + "path": [ + "0x5f35dce98ba4fba25530a026ed80b2cecdaa31091ba4958b99b52ea1d068adad", + "0x15baffb1b0f3a33541686a8c657aa2b592994a26c053479b3aedfdd303473675", + "0xf9735da6e2c0e7f08a672602e23a4b3d899b12756e9e6ea171f19fa8f93ec4d7", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + }, + { + "leaf": "0x8b6e037544bd6f5b933519214ac01249d909a992255c93dd2fad4ca2fe7d84fa", + "index": 4, + "path": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x8c1f4f82a62770b5cd35ea9d7dd4fcdea20e427b80be264b1f54d63464fbf74b", + "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", + "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", + "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", + "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", + "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", + "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", + "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", + "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", + "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", + "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", + "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", + "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", + "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", + "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", + "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", + "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", + "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", + "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", + "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", + "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", + "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", + "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", + "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", + "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", + "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", + "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", + "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", + "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", + "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" + ] + } + ] + } +] diff --git a/primitives/nomad/merkle/src/error.rs b/primitives/nomad/merkle/src/error.rs new file mode 100644 index 000000000..d25209c72 --- /dev/null +++ b/primitives/nomad/merkle/src/error.rs @@ -0,0 +1,32 @@ +use primitive_types::H256; + +/// Tree Errors +#[derive(Debug, thiserror_no_std::Error, Clone, Copy)] +pub enum VerifyingError { + /// Failed proof verification + #[error("Proof verification failed. Root is {expected}, produced is {actual}")] + #[allow(dead_code)] + VerificationFailed { + /// The expected root (this tree's current root) + expected: H256, + /// The root produced by branch evaluation + actual: H256, + }, +} + +/// Error type for merkle tree ops. +#[derive(Debug, PartialEq, Clone, Copy, thiserror_no_std::Error)] +pub enum IngestionError { + /// Trying to push in a leaf + #[error("Trying to push in a leaf")] + LeafReached, + /// No more space in the MerkleTree + #[error("No more space in the MerkleTree")] + MerkleTreeFull, + /// MerkleTree is invalid + #[error("MerkleTree is invalid")] + Invalid, + /// Incorrect Depth provided + #[error("Incorrect Depth provided")] + DepthTooSmall, +} diff --git a/primitives/nomad/merkle/src/lib.rs b/primitives/nomad/merkle/src/lib.rs new file mode 100644 index 000000000..4ae38ce81 --- /dev/null +++ b/primitives/nomad/merkle/src/lib.rs @@ -0,0 +1,84 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_debug_implementations)] +#![warn(missing_copy_implementations)] + +extern crate alloc; + +/// Hashing utils +pub mod utils; + +/// Common error types for the merkle trees. +pub mod error; + +/// A lightweight incremental merkle, suitable for running on-chain. Stores O +/// (1) data +pub mod light; +/// Merkle Proof struct +pub mod proof; + +/// Test utils +#[cfg(test)] +pub(crate) mod test_utils; + +use primitive_types::{H256, U256}; + +/// Tree depth +pub const TREE_DEPTH: usize = 32; +/// An incremental Nomad protocol standard-depth tree +pub type NomadLightMerkle = light::LightMerkle; +/// A Nomad protocol standard-depth proof +pub type NomadProof = proof::Proof; + +pub use error::*; +pub use light::*; +pub use proof::*; +pub use utils::*; + +lazy_static::lazy_static! { + /// A cache of the zero hashes for each layer of the tree. + pub static ref ZERO_HASHES: [H256; TREE_DEPTH + 1] = { + let mut hashes = [H256::zero(); TREE_DEPTH + 1]; + for i in 0..TREE_DEPTH { + hashes[i + 1] = hash_concat(hashes[i], hashes[i]); + } + hashes + }; +} + +/// A merkle proof +pub trait MerkleProof { + /// Calculate the merkle root of this proof's branch + fn root(&self) -> H256; +} + +/// A simple trait for merkle-based accumulators +pub trait Merkle: core::fmt::Debug + Default { + /// A proof of some leaf in this tree + type Proof: MerkleProof; + + /// The maximum number of elements the tree can ingest + fn max_elements() -> U256; + + /// The number of elements currently in the tree + fn count(&self) -> u32; + + /// Calculate the root hash of this Merkle tree. + fn root(&self) -> H256; + + /// Get the tree's depth. + fn depth(&self) -> usize; + + /// Push a leaf to the tree + fn ingest(&mut self, element: H256) -> Result; + + /// Verify a proof against this tree's root. + fn verify(&self, proof: &Self::Proof) -> Result<(), VerifyingError> { + let actual = proof.root(); + let expected = self.root(); + if expected == actual { + Ok(()) + } else { + Err(VerifyingError::VerificationFailed { expected, actual }) + } + } +} diff --git a/primitives/nomad/merkle/src/light.rs b/primitives/nomad/merkle/src/light.rs new file mode 100644 index 000000000..241dba9c3 --- /dev/null +++ b/primitives/nomad/merkle/src/light.rs @@ -0,0 +1,203 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use primitive_types::{H256, U256}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_core::RuntimeDebug; + +use super::{ + error::IngestionError, utils::hash_concat, Merkle, MerkleProof, Proof, TREE_DEPTH, ZERO_HASHES, +}; + +/// An incremental merkle tree, modeled on the eth2 deposit contract +#[derive(Clone, Copy, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct LightMerkle { + #[cfg_attr(feature = "std", serde(with = "arrays"))] + branch: [H256; N], + count: u32, // TODO: is this reasonable over usize due to scale limitations +} + +impl Default for LightMerkle { + fn default() -> Self { + let mut branch: [H256; N] = [Default::default(); N]; + branch + .iter_mut() + .enumerate() + .for_each(|(i, elem)| *elem = ZERO_HASHES[i]); + Self { branch, count: 0 } + } +} + +impl Merkle for LightMerkle { + type Proof = Proof; + + /// Return the maximum number of leaves in this tree + fn max_elements() -> U256 { super::utils::max_leaves(N) } + + fn count(&self) -> u32 { self.count } + + fn root(&self) -> H256 { + let mut node: H256 = Default::default(); + let mut size = self.count; + + self.branch.iter().enumerate().for_each(|(i, elem)| { + node = if (size & 1) == 1 { + super::utils::hash_concat(elem, node) + } else { + super::utils::hash_concat(node, ZERO_HASHES[i]) + }; + size /= 2; + }); + + node + } + + fn depth(&self) -> usize { N } + + fn ingest(&mut self, element: H256) -> Result { + let mut node = element; + if Self::max_leaves() <= self.count.into() { + return Err(IngestionError::MerkleTreeFull); + } + assert!(self.count < u32::MAX); + self.count += 1; + let mut size = self.count; + for i in 0..TREE_DEPTH { + if (size & 1) == 1 { + self.branch[i] = node; + return Ok(self.root()); + } + node = hash_concat(self.branch[i], node); + size /= 2; + } + unreachable!() + } +} + +impl LightMerkle { + /// Return the maximum number of leaves in this tree + pub fn max_leaves() -> U256 { super::utils::max_leaves(N) } + + /// Instantiate a new tree with a known depth and a starting leaf-set + pub fn from_leaves(leaves: &[H256]) -> Self { + let mut tree = Self::default(); + + for leaf in leaves.iter() { + tree.ingest(*leaf).unwrap(); + } + + tree + } + + /// Calculate the initital root of a tree of this depth + pub fn initial_root() -> H256 { LightMerkle::::default().root() } + + /// Get the leading-edge branch. + pub fn branch(&self) -> &[H256; N] { &self.branch } + + /// Verify a incremental merkle proof of inclusion + pub fn verify(&self, proof: &Proof) -> bool { proof.root() == self.root() } +} + +#[cfg(feature = "std")] +mod arrays { + use std::{convert::TryInto, marker::PhantomData}; + + use serde::{ + de::{SeqAccess, Visitor}, + ser::SerializeTuple, + Deserialize, Deserializer, Serialize, Serializer, + }; + pub fn serialize( + data: &[T; N], + ser: S, + ) -> Result { + let mut s = ser.serialize_tuple(N)?; + for item in data { + s.serialize_element(item)?; + } + s.end() + } + + struct ArrayVisitor(PhantomData); + + impl<'de, T, const N: usize> Visitor<'de> for ArrayVisitor + where + T: Deserialize<'de>, + { + type Value = [T; N]; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str(&format!("an array of length {}", N)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + // can be optimized using MaybeUninit + let mut data = Vec::with_capacity(N); + for _ in 0..N { + match (seq.next_element())? { + Some(val) => data.push(val), + None => return Err(serde::de::Error::invalid_length(N, &self)), + } + } + match data.try_into() { + Ok(arr) => Ok(arr), + Err(_) => unreachable!(), + } + } + } + pub fn deserialize<'de, D, T, const N: usize>(deserializer: D) -> Result<[T; N], D::Error> + where + D: Deserializer<'de>, + T: Deserialize<'de>, + { + deserializer.deserialize_tuple(N, ArrayVisitor::(PhantomData)) + } +} + +#[cfg(test)] +mod test { + use ethers_core::utils::hash_message; + + use super::*; + use crate::{test_utils, NomadLightMerkle}; + + #[test] + fn it_calculates_the_initial_root() { + assert_eq!( + NomadLightMerkle::initial_root(), + "0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757" + .parse() + .unwrap() + ); + } + + #[test] + fn it_computes_branch_roots() { + let test_cases = test_utils::load_merkle_test_json(); + for test_case in test_cases.iter() { + let mut tree = NomadLightMerkle::default(); + // insert the leaves + for leaf in test_case.leaves.iter() { + // TODO: ethers core and crate have different primitive types + // versions. Must get inner bytes and call into(). + let hashed_leaf = hash_message(leaf).0.into(); + tree.ingest(hashed_leaf).expect("!ingest"); + } + // assert the tree has the proper leaf count + assert_eq!(tree.count() as usize, test_case.leaves.len()); + // assert the tree generates the proper root + let root = tree.root(); // root is type H256 + assert_eq!(root, test_case.expected_root); + for n in 0..test_case.leaves.len() { + // check that the tree can verify the proof for this leaf + assert!(tree.verify(&test_case.proofs[n])); + } + } + } +} diff --git a/primitives/nomad/merkle/src/proof.rs b/primitives/nomad/merkle/src/proof.rs new file mode 100644 index 000000000..ca2cb5cdb --- /dev/null +++ b/primitives/nomad/merkle/src/proof.rs @@ -0,0 +1,58 @@ +use primitive_types::H256; + +use super::{merkle_root_from_branch, MerkleProof}; + +/// A merkle proof object. The leaf, its path to the root, and its index in the +/// tree. +#[derive(Debug)] +#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] +pub struct Proof { + /// The leaf + pub leaf: H256, + /// The index + pub index: usize, + /// The merkle branch + #[cfg_attr(test, serde(with = "const_array_serde"))] + pub path: [H256; N], +} + +#[cfg(test)] +mod const_array_serde { + use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serializer}; + + use super::H256; + + pub fn serialize(item: &[H256; N], serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(N))?; + for i in item { + seq.serialize_element(i)?; + } + seq.end() + } + + pub fn deserialize<'de, D, const N: usize>(d: D) -> Result<[H256; N], D::Error> + where + D: Deserializer<'de>, + { + let v: Vec = Deserialize::deserialize(d)?; + if v.len() != N { + Err(serde::de::Error::custom(format!( + "Expected a sequence with {} elements. Got {} elements", + N, + v.len() + ))) + } else { + let mut h: [H256; N] = [Default::default(); N]; + h.copy_from_slice(&v[..N]); + Ok(h) + } + } +} + +impl MerkleProof for Proof { + /// Calculate the merkle root produced by evaluating the proof + fn root(&self) -> H256 { merkle_root_from_branch(self.leaf, self.path.as_ref(), N, self.index) } +} diff --git a/primitives/nomad/merkle/src/test_utils.rs b/primitives/nomad/merkle/src/test_utils.rs new file mode 100644 index 000000000..6d953cd20 --- /dev/null +++ b/primitives/nomad/merkle/src/test_utils.rs @@ -0,0 +1,29 @@ +#![cfg(test)] + +use std::{fs::File, io::Read}; + +use primitive_types::H256; + +use crate::NomadProof; + +/// Struct representing a single merkle test case +#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(test, serde(rename_all = "camelCase"))] +pub struct MerkleTestCase { + /// Test case name + pub test_name: String, + /// Leaves of merkle tree + pub leaves: Vec, + /// Proofs for leaves in tree + pub proofs: Vec, + /// Root of tree + pub expected_root: H256, +} + +/// Reads merkle test case json file and returns a vector of `MerkleTestCase`s +pub fn load_merkle_test_json() -> Vec { + let mut file = File::open("fixtures/merkle.json").unwrap(); + let mut data = String::new(); + file.read_to_string(&mut data).unwrap(); + serde_json::from_str(&data).unwrap() +} diff --git a/primitives/nomad/merkle/src/utils.rs b/primitives/nomad/merkle/src/utils.rs new file mode 100644 index 000000000..89324e31e --- /dev/null +++ b/primitives/nomad/merkle/src/utils.rs @@ -0,0 +1,39 @@ +use primitive_types::{H256, U256}; +use tiny_keccak::{Hasher, Keccak}; + +/// Return the keccak256 digest of the preimage +pub fn hash(preimage: impl AsRef<[u8]>) -> H256 { + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(preimage.as_ref()); + hasher.finalize(&mut output); + output.into() +} + +/// Return the keccak256 disgest of the concatenation of the arguments +pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { + let mut vec = left.as_ref().to_vec(); + vec.extend_from_slice(right.as_ref()); + hash(vec) +} + +/// Max number of leaves in a tree +pub(crate) fn max_leaves(n: usize) -> U256 { U256::from(2).pow(n.into()) - 1 } + +/// Compute a root hash from a leaf and a Merkle proof. +pub fn merkle_root_from_branch(leaf: H256, branch: &[H256], depth: usize, index: usize) -> H256 { + assert_eq!(branch.len(), depth, "proof length should equal depth"); + + let mut current = leaf; + + for (i, next) in branch.iter().enumerate().take(depth) { + let ith_bit = (index >> i) & 0x01; + if ith_bit == 1 { + current = hash_concat(next, current); + } else { + current = hash_concat(current, next); + } + } + + current +} diff --git a/primitives/nomad/nomad-base/Cargo.toml b/primitives/nomad/nomad-base/Cargo.toml new file mode 100644 index 000000000..aa216399b --- /dev/null +++ b/primitives/nomad/nomad-base/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "nomad-base" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Substrate +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false } +sp-core = { version = "4.0.0-dev", default-features = false } +sp-io = { version = "4.0.0-dev", default-features = false } +frame-support = { version = "4.0.0-dev", default-features = false } +parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } + +primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info", "codec"] } +tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } +signature = { path = "../signature", default-features = false } + +nomad-core = { path = "../nomad-core", default-features = false } + +[dependencies.serde] +version = "1.0" +default-features = false +optional = true +features = ["derive"] + +[dependencies.ethers-signers] +version = "0.13.0" +default-features = false +optional = true + +[dependencies.once_cell] +version = "1.8.0" +default-features = false +optional = true + +[features] +default = ["std"] +std = [ + "serde", + "primitive-types/serde", + "codec/std", + "scale-info/std", + "frame-support/std", + "nomad-core/std" +] +testing = [ + "ethers-signers", + "once_cell", + "nomad-core/testing", + "signature/testing", +] \ No newline at end of file diff --git a/primitives/nomad/nomad-base/src/lib.rs b/primitives/nomad/nomad-base/src/lib.rs new file mode 100644 index 000000000..4203cf0c6 --- /dev/null +++ b/primitives/nomad/nomad-base/src/lib.rs @@ -0,0 +1,123 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::pallet_prelude::*; +use nomad_core::{home_domain_hash, to_eth_signed_message_hash, NomadState, SignedUpdate, Update}; +use primitive_types::{H160, H256}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use signature::SignatureError; + +#[cfg(feature = "testing")] +pub mod testing; + +#[derive(Clone, Copy, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct NomadBase { + pub state: NomadState, + pub local_domain: u32, + pub committed_root: H256, + pub updater: H160, +} + +impl Default for NomadBase { + fn default() -> Self { + Self { + state: NomadState::Active, + local_domain: Default::default(), + committed_root: Default::default(), + updater: Default::default(), + } + } +} + +pub enum NomadBaseError { + FailedInitialization, +} + +impl NomadBase { + pub fn new(local_domain: u32, committed_root: H256, updater: H160) -> Self { + Self { + state: Default::default(), + local_domain, + committed_root, + updater, + } + } + + pub fn state(&self) -> NomadState { self.state } + + pub fn local_domain(&self) -> u32 { self.local_domain } + + pub fn committed_root(&self) -> H256 { self.committed_root } + + pub fn updater(&self) -> H160 { self.updater } + + pub fn home_domain_hash(&self) -> H256 { home_domain_hash(self.local_domain()) } + + pub fn set_state(&mut self, new_state: NomadState) { self.state = new_state } + + pub fn set_updater(&mut self, new_updater: H160) { self.updater = new_updater } + + pub fn set_committed_root(&mut self, new_committed_root: H256) { + self.committed_root = new_committed_root; + } + + pub fn is_updater_signature( + &self, + signed_update: &SignedUpdate, + ) -> Result { + let supposed_signing_hash = Update { + home_domain: self.local_domain, + previous_root: signed_update.previous_root(), + new_root: signed_update.new_root(), + } + .signing_hash(); + + let digest = to_eth_signed_message_hash(&supposed_signing_hash); + signed_update + .signature + .recover(digest) + .map(|a| a == self.updater) + } +} + +#[cfg(test)] +mod test { + use nomad_core::test_utils::Updater; + + use super::*; + #[cfg(feature = "testing")] + use crate::testing::{FAKE_UPDATER, TEST_NOMAD_BASE, TEST_UPDATER, TEST_UPDATER_PRIVKEY}; + + #[test] + #[cfg(feature = "testing")] + fn it_accepts_valid_signature() { + let valid_signed = TEST_UPDATER.sign_update(H256::repeat_byte(0), H256::repeat_byte(1)); + assert!( + TEST_NOMAD_BASE.is_updater_signature(&valid_signed).unwrap(), + "should have passed on valid signature" + ); + } + + #[test] + #[cfg(feature = "testing")] + fn it_rejects_invalid_signature() { + let invalid_signed = FAKE_UPDATER.sign_update(H256::repeat_byte(0), H256::repeat_byte(1)); + assert!( + !TEST_NOMAD_BASE + .is_updater_signature(&invalid_signed) + .unwrap(), + "should have failed on invalid signature" + ); + + let other_updater = Updater::new(9999, TEST_UPDATER_PRIVKEY.parse().unwrap()); + let wrong_domain_signed = + other_updater.sign_update(H256::repeat_byte(0), H256::repeat_byte(1)); + assert!( + !TEST_NOMAD_BASE + .is_updater_signature(&wrong_domain_signed) + .unwrap(), + "should have failed on invalid signature" + ); + } +} diff --git a/primitives/nomad/nomad-base/src/testing.rs b/primitives/nomad/nomad-base/src/testing.rs new file mode 100644 index 000000000..1aa8ee0dc --- /dev/null +++ b/primitives/nomad/nomad-base/src/testing.rs @@ -0,0 +1,32 @@ +use ethers_signers::LocalWallet; +use nomad_core::test_utils::Updater; +use once_cell::sync::Lazy; + +use crate::NomadBase; + +pub const TEST_LOCAL_DOMAIN: u32 = 1111; +pub const TEST_UPDATER_PRIVKEY: &str = + "1111111111111111111111111111111111111111111111111111111111111111"; + +pub static TEST_UPDATER: Lazy = Lazy::new(|| { + let signer: LocalWallet = TEST_UPDATER_PRIVKEY.parse().unwrap(); + + Updater::new(TEST_LOCAL_DOMAIN, signer) +}); + +pub const FAKE_UPDATER_PRIVKEY: &str = + "2222222222222222222222222222222222222222222222222222222222222222"; + +pub static FAKE_UPDATER: Lazy = Lazy::new(|| { + let signer: LocalWallet = FAKE_UPDATER_PRIVKEY.parse().unwrap(); + + Updater::new(TEST_LOCAL_DOMAIN, signer) +}); + +pub static TEST_NOMAD_BASE: Lazy = Lazy::new(|| { + NomadBase::new( + TEST_LOCAL_DOMAIN, + Default::default(), + TEST_UPDATER.address(), + ) +}); diff --git a/primitives/nomad/nomad-core/Cargo.toml b/primitives/nomad/nomad-core/Cargo.toml new file mode 100644 index 000000000..0c0109ac5 --- /dev/null +++ b/primitives/nomad/nomad-core/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "nomad-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Substrate +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false } +sp-core = { version = "4.0.0-dev", default-features = false } +sp-io = { version = "4.0.0-dev", default-features = false } +frame-support = { version = "4.0.0-dev", default-features = false } +parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } + +primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info", "codec"] } +tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } +signature = { path = "../signature", default-features = false } +getrandom = { version = "0.2", default-features = false, features = ["js"] } + +[dependencies.serde] +version = "1.0" +default-features = false +optional = true +features = ["derive"] + +[dependencies.ethers-signers] +version = "0.13.0" +default-features = false +optional = true + +[dependencies.ethers-core] +version = "0.13.0" +default-features = false +optional = true + +[dependencies.async-trait] +version = "0.1.42" +default-features = false +optional = true + +[features] +default = ["std"] +std = [ + "serde", + "primitive-types/serde", + "signature/std", + "codec/std", + "scale-info/std", + "frame-support/std", +] +testing = [ + "ethers-signers", + "ethers-core", + "async-trait", + "signature/testing" +] \ No newline at end of file diff --git a/primitives/nomad/nomad-core/src/lib.rs b/primitives/nomad/nomad-core/src/lib.rs new file mode 100644 index 000000000..a4e8026d1 --- /dev/null +++ b/primitives/nomad/nomad-core/src/lib.rs @@ -0,0 +1,23 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +mod update_v2; + +mod update; +pub use update::*; + +mod state; +pub use state::*; + +mod nomad_message; +pub use nomad_message::*; + +mod typed_message; +pub use typed_message::*; + +mod utils; +pub use utils::*; + +#[cfg(feature = "testing")] +pub mod test_utils; diff --git a/primitives/nomad/nomad-core/src/nomad_message.rs b/primitives/nomad/nomad-core/src/nomad_message.rs new file mode 100644 index 000000000..c701ba6b5 --- /dev/null +++ b/primitives/nomad/nomad-core/src/nomad_message.rs @@ -0,0 +1,44 @@ +use alloc::vec::Vec; + +use frame_support::pallet_prelude::*; +use primitive_types::H256; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +use crate::utils::keccak256; + +/// A full Nomad message +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct NomadMessage { + /// 4 SLIP-44 ID + pub origin: u32, + /// 32 Address in home convention + pub sender: H256, + /// 4 Count of all previous messages to destination + pub nonce: u32, + /// 4 SLIP-44 ID + pub destination: u32, + /// 32 Address in destination convention + pub recipient: H256, + /// 0+ Message contents + pub body: Vec, +} + +impl NomadMessage { + /// Serialize to a vec + pub fn to_vec(&self) -> Vec { + let mut buf = Vec::::new(); + buf.extend_from_slice(&self.origin.to_be_bytes()); + buf.extend_from_slice(&self.sender.as_ref()); + buf.extend_from_slice(&self.nonce.to_be_bytes()); + buf.extend_from_slice(&self.destination.to_be_bytes()); + buf.extend_from_slice(&self.recipient.as_ref()); + buf.extend_from_slice(&self.body); + + buf + } + + /// Get hash of message + pub fn hash(&self) -> H256 { keccak256(self.to_vec()).into() } +} diff --git a/primitives/nomad/nomad-core/src/state.rs b/primitives/nomad/nomad-core/src/state.rs new file mode 100644 index 000000000..a029185f2 --- /dev/null +++ b/primitives/nomad/nomad-core/src/state.rs @@ -0,0 +1,16 @@ +use frame_support::pallet_prelude::*; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum NomadState { + /// Contract is active + Active, + /// Contract has failed + Failed, +} + +impl Default for NomadState { + fn default() -> Self { Self::Active } +} diff --git a/primitives/nomad/nomad-core/src/test_utils.rs b/primitives/nomad/nomad-core/src/test_utils.rs new file mode 100644 index 000000000..70e7bdbf4 --- /dev/null +++ b/primitives/nomad/nomad-core/src/test_utils.rs @@ -0,0 +1,51 @@ +use ethers_core::utils::hash_message; +use ethers_signers::{LocalWallet, Signer}; +use primitive_types::{H160, H256}; +use signature::Signature; + +use crate::{ + update_v2::{SignedUpdateV2, UpdateV2}, + SignedUpdate, Update, +}; + +#[derive(Debug, Clone)] +pub struct Updater { + pub domain: u32, + pub signer: LocalWallet, +} + +impl Updater { + pub fn new(domain: u32, signer: LocalWallet) -> Self { Self { domain, signer } } + + pub fn address(&self) -> H160 { self.signer.address().0.into() } + + fn sign_message_without_eip_155>(&self, message: M) -> Signature { + // Had to reimplement hash and signing to remove async-ness for + // substrate testing + let message = message.as_ref(); + let message_hash = hash_message(message); + let mut signature = self.signer.sign_hash(message_hash); + + signature.v = 28 - (signature.v % 2); + signature.into() + } + + pub fn sign_update(&self, previous_root: H256, new_root: H256) -> SignedUpdate { + let update = Update { + home_domain: self.domain, + previous_root, + new_root, + }; + let signature = self.sign_message_without_eip_155(update.signing_hash()); + SignedUpdate { update, signature } + } + + pub fn sign_update_v2(&self, root: H256) -> SignedUpdateV2 { + let update = UpdateV2 { + home_domain: self.domain, + root, + }; + let signature = self.sign_message_without_eip_155(update.signing_hash()); + SignedUpdateV2 { update, signature } + } +} diff --git a/primitives/nomad/nomad-core/src/typed_message.rs b/primitives/nomad/nomad-core/src/typed_message.rs new file mode 100644 index 000000000..d5e8fffde --- /dev/null +++ b/primitives/nomad/nomad-core/src/typed_message.rs @@ -0,0 +1,20 @@ +use alloc::vec::Vec; + +/// This trait provides structure for encoding a Vec as a xapp message. +/// First byte of Vec is a u8 corresponding to a message type. The remaining +/// bytes make up the message body. +pub trait TypedMessage: AsRef<[u8]> { + type MessageEnum: From; + + /// Return the message type + fn message_type(&self) -> Self::MessageEnum { + let slice: &[u8] = self.as_ref(); + slice[0].into() + } + + /// Return the message body after the type byte + fn message_body(&self) -> Vec { + let slice: &[u8] = self.as_ref(); + slice[1..].to_vec() + } +} diff --git a/primitives/nomad/nomad-core/src/update.rs b/primitives/nomad/nomad-core/src/update.rs new file mode 100644 index 000000000..0625bfd40 --- /dev/null +++ b/primitives/nomad/nomad-core/src/update.rs @@ -0,0 +1,90 @@ +use frame_support::pallet_prelude::*; +use primitive_types::{H160, H256}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use signature::{hash_message, Signature, SignatureError}; +use tiny_keccak::{Hasher, Keccak}; + +use crate::utils::home_domain_hash; + +/// Nomad update +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Update { + /// The home chain + pub home_domain: u32, + /// The previous root + pub previous_root: H256, + /// The new root + pub new_root: H256, +} + +impl Update { + /// Get signing hash for update + pub fn signing_hash(&self) -> H256 { + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(home_domain_hash(self.home_domain).as_ref()); + hasher.update(self.previous_root.as_ref()); + hasher.update(self.new_root.as_ref()); + hasher.finalize(&mut output); + output.into() + } + + fn prepended_hash(&self) -> H256 { hash_message(self.signing_hash()) } +} + +/// A Signed Nomad Update +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct SignedUpdate { + /// The update + pub update: Update, + /// The signature + pub signature: Signature, +} + +impl SignedUpdate { + pub fn previous_root(&self) -> H256 { self.update.previous_root } + + pub fn new_root(&self) -> H256 { self.update.new_root } + + /// Recover the Ethereum address of the signer + pub fn recover(&self) -> Result { + Ok(self.signature.recover(self.update.prepended_hash())?) + } + + /// Check whether a message was signed by a specific address + pub fn verify(&self, signer: H160) -> Result<(), SignatureError> { + Ok(self + .signature + .verify(self.update.prepended_hash(), signer)?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(feature = "testing")] + use crate::test_utils::Updater; + + pub const TEST_UPDATER_PRIVKEY: &str = + "1111111111111111111111111111111111111111111111111111111111111111"; + + #[test] + #[cfg(feature = "testing")] + fn recover_valid_update() { + use ethers_signers::{LocalWallet, Signer}; + + let wallet: LocalWallet = TEST_UPDATER_PRIVKEY.parse().unwrap(); + println!("Wallet address: {:x}", wallet.address()); + + let updater = Updater::new(1000, TEST_UPDATER_PRIVKEY.parse().unwrap()); + let signed_update = updater.sign_update(H256::repeat_byte(0), H256::repeat_byte(1)); + + let recovered = signed_update.recover().expect("!recover"); + println!("Recovered address: {:x}", recovered); + + signed_update.verify(updater.address()).expect("!sig"); + } +} diff --git a/primitives/nomad/nomad-core/src/update_v2.rs b/primitives/nomad/nomad-core/src/update_v2.rs new file mode 100644 index 000000000..208a4ec67 --- /dev/null +++ b/primitives/nomad/nomad-core/src/update_v2.rs @@ -0,0 +1,85 @@ +#![allow(dead_code)] + +use frame_support::pallet_prelude::*; +use primitive_types::{H160, H256}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use signature::{hash_message, Signature, SignatureError}; +use tiny_keccak::{Hasher, Keccak}; + +use crate::utils::home_domain_hash; + +/// Nomad update +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct UpdateV2 { + /// The home chain + pub home_domain: u32, + /// The new root + pub root: H256, +} + +impl UpdateV2 { + /// Get signing hash for update + pub fn signing_hash(&self) -> H256 { + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(home_domain_hash(self.home_domain).as_ref()); + hasher.update(self.root.as_ref()); + hasher.finalize(&mut output); + output.into() + } + + fn prepended_hash(&self) -> H256 { hash_message(self.signing_hash()) } +} + +/// A Signed Nomad Update +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct SignedUpdateV2 { + /// The update + pub update: UpdateV2, + /// The signature + pub signature: Signature, +} + +impl SignedUpdateV2 { + /// Recover the Ethereum address of the signer + pub fn recover(&self) -> Result { + Ok(self.signature.recover(self.update.prepended_hash())?) + } + + /// Check whether a message was signed by a specific address + pub fn verify(&self, signer: H160) -> Result<(), SignatureError> { + Ok(self + .signature + .verify(self.update.prepended_hash(), signer)?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(feature = "testing")] + use crate::test_utils::Updater; + + pub const TEST_UPDATER_PRIVKEY: &str = + "1111111111111111111111111111111111111111111111111111111111111111"; + + #[test] + #[cfg(feature = "testing")] + fn recover_valid_update_v2() { + use ethers_signers::{LocalWallet, Signer}; + + let wallet: LocalWallet = TEST_UPDATER_PRIVKEY.parse().unwrap(); + println!("Wallet address: {:x}", wallet.address()); + + let updater = Updater::new(1000, TEST_UPDATER_PRIVKEY.parse().unwrap()); + let signed_update = updater.sign_update_v2(H256::repeat_byte(1)); + + let recovered = signed_update.recover().expect("!recover"); + println!("Recovered address: {:x}", recovered); + + signed_update.verify(updater.address()).expect("!sig"); + } +} diff --git a/primitives/nomad/nomad-core/src/utils.rs b/primitives/nomad/nomad-core/src/utils.rs new file mode 100644 index 000000000..afda25934 --- /dev/null +++ b/primitives/nomad/nomad-core/src/utils.rs @@ -0,0 +1,45 @@ +use primitive_types::H256; +use tiny_keccak::{Hasher, Keccak}; + +const NOMAD_PREFIX: &str = "NOMAD"; +const ETH_PREFIX: &str = "\x19Ethereum Signed Message:\n32"; + +/// Computes hash of home domain concatenated with "NOMAD" +pub fn home_domain_hash(home_domain: u32) -> H256 { + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(home_domain.to_be_bytes().as_ref()); + hasher.update(NOMAD_PREFIX.as_bytes()); + hasher.finalize(&mut output); + output.into() +} + +/// Compute the Keccak-256 hash of input bytes. +pub fn keccak256(bytes: S) -> [u8; 32] +where + S: AsRef<[u8]>, +{ + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(bytes.as_ref()); + hasher.finalize(&mut output); + output +} + +/// Hash a message according to EIP-191 with the ethereum signed message prefix. +pub fn to_eth_signed_message_hash(hash: &H256) -> H256 { + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(ETH_PREFIX.as_bytes()); + hasher.update(hash.as_bytes()); + hasher.finalize(&mut output); + output.into() +} + +/// Destination and destination-specific nonce combined in single field ( +/// (destination << 32) & nonce) +pub fn destination_and_nonce(destination: u32, nonce: u32) -> u64 { + assert!(destination < u32::MAX); + assert!(nonce < u32::MAX); + ((destination as u64) << 32) | nonce as u64 +} diff --git a/primitives/nomad/signature/Cargo.toml b/primitives/nomad/signature/Cargo.toml new file mode 100644 index 000000000..bc5159221 --- /dev/null +++ b/primitives/nomad/signature/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "signature" +version = "0.1.0" +edition = "2021" +authors = ["Luke Tchang "] +license = "MIT OR Apache-2.0" +readme = "README.md" +repository = "https://github.com/ltchang2019/no-std-eth-signature" +description = """ +`ethers-rs` signature implemented as no_std. +""" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Substrate +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false } +sp-core = { version = "4.0.0-dev", default-features = false } +sp-io = { version = "4.0.0-dev", default-features = false } +frame-support = { version = "4.0.0-dev", default-features = false } +parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info", "codec"] } +rlp = { version = "0.5.0", default-features = false } +ethabi = { version = "17.0.0", default-features = false, features = ["rlp"] } +arrayvec = { version = "0.7.2", default-features = false } +rlp-derive = { version = "0.1.0", default-features = false } + +# crypto +elliptic-curve = { version = "0.11.12", default-features = false } +generic-array = { version = "0.14.5", default-features = false } +k256 = { version = "0.10.4", default-features = false, features = ["keccak256", "ecdsa"] } +tiny-keccak = { version = "2.0.2", default-features = false } + +# misc +thiserror-no-std = "2.0.1" +hex = { version = "0.4.3", default-features = false } +once_cell = { version = "1.12.0", optional = true } + +[dependencies.serde] +version = "1.0" +default-features = false +optional = true +features = ["derive"] + +[dependencies.ethers-core] +version = "0.13.0" +default-features = false +optional = true + +[dependencies.byte-slice-cast] +version = "1.2.1" +default-features = false +optional = true + +[features] +default = ["std"] +std = [ + "serde", + "primitive-types/serde", + "codec/std", + "scale-info/std", + "frame-support/std", +] +testing = ["ethers-core", "byte-slice-cast"] \ No newline at end of file diff --git a/primitives/nomad/signature/README.md b/primitives/nomad/signature/README.md new file mode 100644 index 000000000..6b2c9f824 --- /dev/null +++ b/primitives/nomad/signature/README.md @@ -0,0 +1 @@ +`ethers-rs` signature implemented with as no_std. diff --git a/primitives/nomad/signature/src/lib.rs b/primitives/nomad/signature/src/lib.rs new file mode 100644 index 000000000..0d56153e0 --- /dev/null +++ b/primitives/nomad/signature/src/lib.rs @@ -0,0 +1,12 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +mod signature; +pub use crate::signature::*; + +mod utils; +pub use utils::*; + +extern crate thiserror_no_std as thiserror; + +#[macro_use] +extern crate alloc; diff --git a/primitives/nomad/signature/src/signature.rs b/primitives/nomad/signature/src/signature.rs new file mode 100644 index 000000000..2f00cacfa --- /dev/null +++ b/primitives/nomad/signature/src/signature.rs @@ -0,0 +1,286 @@ +// Code adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/api/accounts.rs + +use alloc::{borrow::ToOwned, string::String, vec::Vec}; +use core::{convert::TryFrom, fmt, str::FromStr}; + +use elliptic_curve::{consts::U32, sec1::ToEncodedPoint}; +use frame_support::pallet_prelude::*; +use generic_array::GenericArray; +use k256::{ + ecdsa::{ + recoverable::{Id as RecoveryId, Signature as RecoverableSignature}, + Error as K256SignatureError, Signature as K256Signature, + }, + PublicKey as K256PublicKey, +}; +use primitive_types::{H160, H256, U256}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::utils::hash_message; + +type Address = H160; + +/// An error involving a signature. +#[derive(Debug, Error)] +pub enum SignatureError { + /// Invalid length, secp256k1 signatures are 65 bytes + #[error("invalid signature length, got {0}, expected 65")] + InvalidLength(usize), + /// When parsing a signature from string to hex + #[error(transparent)] + DecodingError(#[from] hex::FromHexError), + /// Thrown when signature verification failed (i.e. when the address that + /// produced the signature did not match the expected address) + #[error("Signature verification failed. Expected {0:?}, got {1:?}")] + VerificationError(Address, Address), + /// Internal error during signature recovery + #[error(transparent)] + K256Error(#[from] K256SignatureError), + /// Error in recovering public key from signature + #[error("Public key recovery error")] + RecoveryError, +} + +/// Recovery message data. +/// +/// The message data can either be a binary message that is first hashed +/// according to EIP-191 and then recovered based on the signature or a +/// precomputed hash. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum RecoveryMessage { + /// Message bytes + Data(Vec), + /// Message hash + Hash(H256), +} + +/// An ECDSA signature +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Signature { + /// R value + pub r: U256, + /// S Value + pub s: U256, + /// V value + pub v: u64, +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let sig = <[u8; 65]>::from(self); + write!(f, "{}", hex::encode(&sig[..])) + } +} + +impl Signature { + /// Verifies that signature on `message` was produced by `address` + pub fn verify(&self, message: M, address: A) -> Result<(), SignatureError> + where + M: Into, + A: Into
, + { + let address = address.into(); + let recovered = self.recover(message)?; + if recovered != address { + return Err(SignatureError::VerificationError(address, recovered)); + } + + Ok(()) + } + + /// Recovers the Ethereum address which was used to sign the given message. + /// + /// Recovery signature data uses 'Electrum' notation, this means the `v` + /// value is expected to be either `27` or `28`. + pub fn recover(&self, message: M) -> Result + where + M: Into, + { + let message = message.into(); + let message_hash = match message { + RecoveryMessage::Data(ref message) => hash_message(message), + RecoveryMessage::Hash(hash) => hash, + }; + + let (recoverable_sig, _recovery_id) = self.as_signature()?; + let verify_key = + recoverable_sig.recover_verify_key_from_digest_bytes(message_hash.as_ref().into())?; + + let public_key = K256PublicKey::from(&verify_key); + let public_key = public_key.to_encoded_point(/* compress = */ false); + let public_key = public_key.as_bytes(); + debug_assert_eq!(public_key[0], 0x04); + let hash = crate::utils::keccak256(&public_key[1..]); + Ok(Address::from_slice(&hash[12..])) + } + + /// Retrieves the recovery signature. + fn as_signature(&self) -> Result<(RecoverableSignature, RecoveryId), SignatureError> { + let recovery_id = self.recovery_id()?; + let signature = { + let mut r_bytes = [0u8; 32]; + let mut s_bytes = [0u8; 32]; + self.r.to_big_endian(&mut r_bytes); + self.s.to_big_endian(&mut s_bytes); + let gar: &GenericArray = GenericArray::from_slice(&r_bytes); + let gas: &GenericArray = GenericArray::from_slice(&s_bytes); + let sig = K256Signature::from_scalars(*gar, *gas)?; + RecoverableSignature::new(&sig, recovery_id)? + }; + + Ok((signature, recovery_id)) + } + + /// Retrieve the recovery ID. + pub fn recovery_id(&self) -> Result { + let standard_v = normalize_recovery_id(self.v); + Ok(RecoveryId::new(standard_v)?) + } + + /// Copies and serializes `self` into a new `Vec` with the recovery id included + #[allow(clippy::wrong_self_convention)] + pub fn to_vec(&self) -> Vec { self.into() } +} + +fn normalize_recovery_id(v: u64) -> u8 { + match v { + 0 => 0, + 1 => 1, + 27 => 0, + 28 => 1, + v if v >= 35 => ((v - 1) % 2) as _, + _ => 4, + } +} + +impl<'a> TryFrom<&'a [u8]> for Signature { + type Error = SignatureError; + + /// Parses a raw signature which is expected to be 65 bytes long where + /// the first 32 bytes is the `r` value, the second 32 bytes the `s` value + /// and the final byte is the `v` value in 'Electrum' notation. + fn try_from(bytes: &'a [u8]) -> Result { + if bytes.len() != 65 { + return Err(SignatureError::InvalidLength(bytes.len())); + } + + let v = bytes[64]; + let r = U256::from_big_endian(&bytes[0..32]); + let s = U256::from_big_endian(&bytes[32..64]); + + Ok(Signature { r, s, v: v.into() }) + } +} + +impl FromStr for Signature { + type Err = SignatureError; + + fn from_str(s: &str) -> Result { + let s = s.strip_prefix("0x").unwrap_or(s); + let bytes = hex::decode(s)?; + Signature::try_from(&bytes[..]) + } +} + +impl From<&Signature> for [u8; 65] { + fn from(src: &Signature) -> [u8; 65] { + let mut sig = [0u8; 65]; + let mut r_bytes = [0u8; 32]; + let mut s_bytes = [0u8; 32]; + src.r.to_big_endian(&mut r_bytes); + src.s.to_big_endian(&mut s_bytes); + sig[..32].copy_from_slice(&r_bytes); + sig[32..64].copy_from_slice(&s_bytes); + // TODO: What if we try to serialize a signature where + // the `v` is not normalized? + sig[64] = src.v as u8; + sig + } +} + +impl From for [u8; 65] { + fn from(src: Signature) -> [u8; 65] { <[u8; 65]>::from(&src) } +} + +impl From<&Signature> for Vec { + fn from(src: &Signature) -> Vec { <[u8; 65]>::from(src).to_vec() } +} + +impl From for Vec { + fn from(src: Signature) -> Vec { <[u8; 65]>::from(&src).to_vec() } +} + +impl From<&[u8]> for RecoveryMessage { + fn from(s: &[u8]) -> Self { s.to_owned().into() } +} + +impl From> for RecoveryMessage { + fn from(s: Vec) -> Self { RecoveryMessage::Data(s) } +} + +impl From<&str> for RecoveryMessage { + fn from(s: &str) -> Self { s.as_bytes().to_owned().into() } +} + +impl From for RecoveryMessage { + fn from(s: String) -> Self { RecoveryMessage::Data(s.into_bytes()) } +} + +impl From<[u8; 32]> for RecoveryMessage { + fn from(hash: [u8; 32]) -> Self { H256(hash).into() } +} + +impl From for RecoveryMessage { + fn from(hash: H256) -> Self { RecoveryMessage::Hash(hash) } +} + +// Want to convert ethers signature into our no-std version in tests +#[cfg(feature = "testing")] +impl From for Signature { + fn from(sig: ethers_core::types::Signature) -> Self { + // ethers-core 0.13.0 uses primitive types 0.11.1, sp-core 4.0.0-dev + // uses primitive types 0.10.1 + let r_bytes: [u8; 32] = sig.r.into(); + let s_bytes: [u8; 32] = sig.s.into(); + + Self { + r: r_bytes.into(), + s: s_bytes.into(), + v: sig.v, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn recover_web3_signature() { + // test vector taken from: + // https://web3js.readthedocs.io/en/v1.2.2/web3-eth-accounts.html#sign + let signature = Signature::from_str( + "b91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c" + ).expect("could not parse signature"); + assert_eq!( + signature.recover("Some data").unwrap(), + Address::from_str("2c7536E3605D9C16a7a3D7b1898e529396a65c23").unwrap() + ); + } + + #[test] + fn signature_from_str() { + let s1 = Signature::from_str( + "0xaa231fbe0ed2b5418e6ba7c19bee2522852955ec50996c02a2fe3e71d30ddaf1645baf4823fea7cb4fcc7150842493847cfb6a6d63ab93e8ee928ee3f61f503500" + ).expect("could not parse 0x-prefixed signature"); + + let s2 = Signature::from_str( + "aa231fbe0ed2b5418e6ba7c19bee2522852955ec50996c02a2fe3e71d30ddaf1645baf4823fea7cb4fcc7150842493847cfb6a6d63ab93e8ee928ee3f61f503500" + ).expect("could not parse non-prefixed signature"); + + assert_eq!(s1, s2); + } +} diff --git a/primitives/nomad/signature/src/utils.rs b/primitives/nomad/signature/src/utils.rs new file mode 100644 index 000000000..eac8cd799 --- /dev/null +++ b/primitives/nomad/signature/src/utils.rs @@ -0,0 +1,35 @@ +//! Various utilities for manipulating Ethereum related dat +use primitive_types::H256; +use tiny_keccak::{Hasher, Keccak}; + +const PREFIX: &str = "\x19Ethereum Signed Message:\n"; + +/// Hash a message according to EIP-191. +/// +/// The data is a UTF-8 encoded string and will enveloped as follows: +/// `"\x19Ethereum Signed Message:\n" + message.length + message` and hashed +/// using keccak256. +pub fn hash_message(message: S) -> H256 +where + S: AsRef<[u8]>, +{ + let message = message.as_ref(); + + let mut eth_message = format!("{}{}", PREFIX, message.len()).into_bytes(); + eth_message.extend_from_slice(message); + + keccak256(ð_message).into() +} + +/// Compute the Keccak-256 hash of input bytes. +// TODO: Add Solidity Keccak256 packing support +pub fn keccak256(bytes: S) -> [u8; 32] +where + S: AsRef<[u8]>, +{ + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(bytes.as_ref()); + hasher.finalize(&mut output); + output +} diff --git a/rpc/kate-rpc/Cargo.toml b/rpc/kate-rpc/Cargo.toml index cbd05ebe0..ab684a77d 100644 --- a/rpc/kate-rpc/Cargo.toml +++ b/rpc/kate-rpc/Cargo.toml @@ -16,7 +16,7 @@ rs_merkle = { version = "1.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0" } -da-primitives= { path = "../../primitives" } +da-primitives= { path = "../../primitives/avail" } kate = { path = "../../kate" } dusk-plonk = "0.8.2" # frame-system = "4.0.0-dev" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index a3eeef620..9f727be5d 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Internal -da-primitives = { path = "../primitives", default-features = false } +da-primitives = { path = "../primitives/avail", default-features = false } da-control = { path = "../pallets/dactr", default-features = false } kate = { path = "../kate", default-features = false } kate-rpc-runtime-api = { path = "../rpc/kate-rpc-runtime-api", default-features = false } From 3ef8ae8ebf194895e4ebfaf05e6280b5b8494172 Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Mon, 12 Sep 2022 13:26:50 -0700 Subject: [PATCH 02/11] patch dependencies to fix build issues --- Cargo.lock | 87 +++++++++++++++++++++++++++++++++++------------------- Cargo.toml | 4 +++ 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f100b58aa..142bb5c41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1961,7 +1961,7 @@ dependencies = [ "serde_json", "sha3 0.10.4", "thiserror", - "uint", + "uint 0.9.3", ] [[package]] @@ -1971,9 +1971,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-rlp", - "impl-serde", + "impl-serde 0.3.2", "tiny-keccak", ] @@ -1984,11 +1984,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ "ethbloom", - "fixed-hash", + "fixed-hash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-rlp", - "impl-serde", + "impl-serde 0.3.2", "primitive-types 0.11.1", - "uint", + "uint 0.9.3", ] [[package]] @@ -2142,6 +2142,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "git+https://github.com/paritytech/parity-common.git?tag=parity-util-mem-v0.10.1#3030a6dd28352a4a12169340d22f130f331e0d12" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.1" @@ -3020,8 +3031,7 @@ dependencies = [ [[package]] name = "impl-codec" version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +source = "git+https://github.com/paritytech/parity-common.git?tag=parity-util-mem-v0.10.1#3030a6dd28352a4a12169340d22f130f331e0d12" dependencies = [ "parity-scale-codec 2.3.1", ] @@ -3044,6 +3054,14 @@ dependencies = [ "rlp", ] +[[package]] +name = "impl-serde" +version = "0.3.1" +source = "git+https://github.com/paritytech/parity-common.git?tag=parity-util-mem-v0.10.1#3030a6dd28352a4a12169340d22f130f331e0d12" +dependencies = [ + "serde", +] + [[package]] name = "impl-serde" version = "0.3.2" @@ -3726,7 +3744,7 @@ dependencies = [ "rand 0.7.3", "sha2 0.9.9", "smallvec", - "uint", + "uint 0.9.3", "unsigned-varint 0.7.1", "void", "wasm-timer", @@ -5356,9 +5374,8 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e7f385d61562f5834282b90aa50b41f38a35cf64d5209b8b05487b50553dbe" +version = "0.3.12" +source = "git+https://github.com/paritytech/parity-db.git?tag=v0.3.12#4e680e18a590ef7826b6d11229bb98448c5ae477" dependencies = [ "blake2-rfc", "crc32fast", @@ -5843,14 +5860,13 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "primitive-types" version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +source = "git+https://github.com/paritytech/parity-common.git?tag=parity-util-mem-v0.10.1#3030a6dd28352a4a12169340d22f130f331e0d12" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0 (git+https://github.com/paritytech/parity-common.git?tag=parity-util-mem-v0.10.1)", "impl-codec 0.5.1", - "impl-serde", + "impl-serde 0.3.1", "scale-info", - "uint", + "uint 0.9.1", ] [[package]] @@ -5859,11 +5875,11 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-codec 0.6.0", "impl-rlp", - "impl-serde", - "uint", + "impl-serde 0.3.2", + "uint 0.9.3", ] [[package]] @@ -8182,7 +8198,7 @@ dependencies = [ "hash-db", "hash256-std-hasher", "hex", - "impl-serde", + "impl-serde 0.3.2", "lazy_static", "libsecp256k1", "log", @@ -8535,7 +8551,7 @@ name = "sp-storage" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.13#afb74de23dfe2994e7ce38c0870efb9734e966f7" dependencies = [ - "impl-serde", + "impl-serde 0.3.2", "parity-scale-codec 2.3.1", "ref-cast", "serde", @@ -8629,7 +8645,7 @@ name = "sp-version" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.13#afb74de23dfe2994e7ce38c0870efb9734e966f7" dependencies = [ - "impl-serde", + "impl-serde 0.3.2", "parity-scale-codec 2.3.1", "parity-wasm 0.42.2", "scale-info", @@ -8879,9 +8895,8 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +version = "1.0.96" +source = "git+https://github.com/dtolnay/syn.git?tag=1.0.96#cb8760bcdcc00e9969a7f2e04816ea9bad6b8252" dependencies = [ "proc-macro2", "quote", @@ -9087,9 +9102,8 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +version = "1.19.2" +source = "git+https://github.com/tokio-rs/tokio?tag=tokio-1.19.2#340c4dc3b2123d0bf5ec2795bd9c157d8a10ccf6" dependencies = [ "bytes 1.1.0", "libc", @@ -9338,8 +9352,8 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 1.0.0", - "rand 0.8.5", + "cfg-if 0.1.10", + "rand 0.7.3", "static_assertions", ] @@ -9355,6 +9369,17 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "uint" +version = "0.9.1" +source = "git+https://github.com/paritytech/parity-common.git?tag=parity-util-mem-v0.10.1#3030a6dd28352a4a12169340d22f130f331e0d12" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "uint" version = "0.9.3" diff --git a/Cargo.toml b/Cargo.toml index 839af0a54..85ec42169 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,10 @@ dusk-plonk = { git = "https://github.com/maticnetwork/plonk.git", branch = "v0.8 frame-system = { path = "pallets/system" } frame-executive = { path = "pallets/executive" } frame-system-rpc-runtime-api = { path = "pallets/system/rpc/runtime-api" } +syn = { git = "https://github.com/dtolnay/syn.git", tag = "1.0.96" } +tokio = { git = "https://github.com/tokio-rs/tokio", tag = "tokio-1.19.2" } +primitive-types = { git = "https://github.com/paritytech/parity-common.git", tag = "parity-util-mem-v0.10.1" } +parity-db = { git = "https://github.com/paritytech/parity-db.git", tag = "v0.3.12" } # Substrate (polkadot-v0.9.13). sc-cli = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.13" } From fdccc161cfb281ce29dabca57c643bf81ce24ec8 Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Wed, 14 Sep 2022 11:37:24 -0700 Subject: [PATCH 03/11] fix panics in merkle primitive --- Cargo.lock | 1 + primitives/avail/src/header.rs | 6 ++--- primitives/avail/src/traits.rs | 5 ++-- primitives/nomad/merkle/Cargo.toml | 1 + primitives/nomad/merkle/src/error.rs | 5 +++- primitives/nomad/merkle/src/lib.rs | 6 ++--- primitives/nomad/merkle/src/light.rs | 39 ++++++++++++++-------------- primitives/nomad/merkle/src/utils.rs | 19 +++++++++++--- 8 files changed, 51 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 142bb5c41..ce3a1b1f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4316,6 +4316,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "static_assertions", "thiserror-no-std", "tiny-keccak", ] diff --git a/primitives/avail/src/header.rs b/primitives/avail/src/header.rs index fc8984600..650be8392 100644 --- a/primitives/avail/src/header.rs +++ b/primitives/avail/src/header.rs @@ -4,7 +4,7 @@ use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_core::{RuntimeDebug, U256}; +use sp_core::{RuntimeDebug, U256, H256}; use sp_runtime::{ traits::{ AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, MaybeFromStr, @@ -276,9 +276,9 @@ where fn set_extrinsics_root(&mut self, root: Self::Root) { self.extrinsics_root = root; } - fn data_root(&self) -> &[u8; 32] { &self.extrinsics_root.data_root } + fn data_root(&self) -> H256 { self.extrinsics_root.data_root.into() } - fn set_data_root(&mut self, data_root: [u8; 32]) { self.extrinsics_root.data_root = data_root; } + fn set_data_root(&mut self, data_root: H256) { self.extrinsics_root.data_root = data_root.into(); } fn data_lookup(&self) -> &DataLookup { &self.app_data_lookup } diff --git a/primitives/avail/src/traits.rs b/primitives/avail/src/traits.rs index 92bc0c3f5..a45d677d6 100644 --- a/primitives/avail/src/traits.rs +++ b/primitives/avail/src/traits.rs @@ -1,3 +1,4 @@ +use sp_core::H256; use sp_runtime::Digest; use sp_std::vec::Vec; @@ -36,8 +37,8 @@ pub trait ExtendedHeader { fn extrinsics_root(&self) -> &Self::Root; fn set_extrinsics_root(&mut self, root: Self::Root); - fn data_root(&self) -> &[u8; 32]; - fn set_data_root(&mut self, root: [u8; 32]); + fn data_root(&self) -> H256; + fn set_data_root(&mut self, root: H256); fn data_lookup(&self) -> &DataLookup; diff --git a/primitives/nomad/merkle/Cargo.toml b/primitives/nomad/merkle/Cargo.toml index 9ac1b3e49..f6ffd5bbe 100644 --- a/primitives/nomad/merkle/Cargo.toml +++ b/primitives/nomad/merkle/Cargo.toml @@ -20,6 +20,7 @@ primitive-types = { version = "0.10.1", default-features = false, features = ["s tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } thiserror-no-std = "2.0.2" +static_assertions = "1.1.0" [dev-dependencies] serde = { version = "1.0", features = ["derive"] } diff --git a/primitives/nomad/merkle/src/error.rs b/primitives/nomad/merkle/src/error.rs index d25209c72..d54bcd085 100644 --- a/primitives/nomad/merkle/src/error.rs +++ b/primitives/nomad/merkle/src/error.rs @@ -16,7 +16,7 @@ pub enum VerifyingError { /// Error type for merkle tree ops. #[derive(Debug, PartialEq, Clone, Copy, thiserror_no_std::Error)] -pub enum IngestionError { +pub enum TreeError { /// Trying to push in a leaf #[error("Trying to push in a leaf")] LeafReached, @@ -29,4 +29,7 @@ pub enum IngestionError { /// Incorrect Depth provided #[error("Incorrect Depth provided")] DepthTooSmall, + /// Integer overflow + #[error("Integer overflow occured")] + IntegerOverflow, } diff --git a/primitives/nomad/merkle/src/lib.rs b/primitives/nomad/merkle/src/lib.rs index 4ae38ce81..d57fce53a 100644 --- a/primitives/nomad/merkle/src/lib.rs +++ b/primitives/nomad/merkle/src/lib.rs @@ -20,7 +20,7 @@ pub mod proof; #[cfg(test)] pub(crate) mod test_utils; -use primitive_types::{H256, U256}; +use primitive_types::H256; /// Tree depth pub const TREE_DEPTH: usize = 32; @@ -57,7 +57,7 @@ pub trait Merkle: core::fmt::Debug + Default { type Proof: MerkleProof; /// The maximum number of elements the tree can ingest - fn max_elements() -> U256; + fn max_elements() -> Result; /// The number of elements currently in the tree fn count(&self) -> u32; @@ -69,7 +69,7 @@ pub trait Merkle: core::fmt::Debug + Default { fn depth(&self) -> usize; /// Push a leaf to the tree - fn ingest(&mut self, element: H256) -> Result; + fn ingest(&mut self, element: H256) -> Result; /// Verify a proof against this tree's root. fn verify(&self, proof: &Self::Proof) -> Result<(), VerifyingError> { diff --git a/primitives/nomad/merkle/src/light.rs b/primitives/nomad/merkle/src/light.rs index 241dba9c3..2641411aa 100644 --- a/primitives/nomad/merkle/src/light.rs +++ b/primitives/nomad/merkle/src/light.rs @@ -1,12 +1,13 @@ use codec::{Decode, Encode, MaxEncodedLen}; -use primitive_types::{H256, U256}; +use frame_support::ensure; +use primitive_types::H256; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::RuntimeDebug; use super::{ - error::IngestionError, utils::hash_concat, Merkle, MerkleProof, Proof, TREE_DEPTH, ZERO_HASHES, + error::TreeError, utils::hash_concat, Merkle, MerkleProof, Proof, TREE_DEPTH, ZERO_HASHES, }; /// An incremental merkle tree, modeled on the eth2 deposit contract @@ -33,7 +34,9 @@ impl Merkle for LightMerkle { type Proof = Proof; /// Return the maximum number of leaves in this tree - fn max_elements() -> U256 { super::utils::max_leaves(N) } + fn max_elements() -> Result { + super::utils::checked_max_leaves(N).ok_or(TreeError::IntegerOverflow) + } fn count(&self) -> u32 { self.count } @@ -55,12 +58,14 @@ impl Merkle for LightMerkle { fn depth(&self) -> usize { N } - fn ingest(&mut self, element: H256) -> Result { + fn ingest(&mut self, element: H256) -> Result { + ensure!( + Self::max_elements()? > self.count, + TreeError::MerkleTreeFull + ); + let mut node = element; - if Self::max_leaves() <= self.count.into() { - return Err(IngestionError::MerkleTreeFull); - } - assert!(self.count < u32::MAX); + self.count += 1; let mut size = self.count; for i in 0..TREE_DEPTH { @@ -71,23 +76,21 @@ impl Merkle for LightMerkle { node = hash_concat(self.branch[i], node); size /= 2; } - unreachable!() + + Err(TreeError::Invalid) } } impl LightMerkle { - /// Return the maximum number of leaves in this tree - pub fn max_leaves() -> U256 { super::utils::max_leaves(N) } - /// Instantiate a new tree with a known depth and a starting leaf-set - pub fn from_leaves(leaves: &[H256]) -> Self { + pub fn from_leaves(leaves: &[H256]) -> Result { let mut tree = Self::default(); for leaf in leaves.iter() { - tree.ingest(*leaf).unwrap(); + tree.ingest(*leaf).map_err(|_| TreeError::MerkleTreeFull)?; } - tree + Ok(tree) } /// Calculate the initital root of a tree of this depth @@ -145,10 +148,8 @@ mod arrays { None => return Err(serde::de::Error::invalid_length(N, &self)), } } - match data.try_into() { - Ok(arr) => Ok(arr), - Err(_) => unreachable!(), - } + data.try_into() + .map_err(|_| serde::de::Error::custom("Failed to convert sized Vec into [T; N]")) } } pub fn deserialize<'de, D, T, const N: usize>(deserializer: D) -> Result<[T; N], D::Error> diff --git a/primitives/nomad/merkle/src/utils.rs b/primitives/nomad/merkle/src/utils.rs index 89324e31e..8f4cfdda1 100644 --- a/primitives/nomad/merkle/src/utils.rs +++ b/primitives/nomad/merkle/src/utils.rs @@ -1,6 +1,8 @@ -use primitive_types::{H256, U256}; +use primitive_types::H256; use tiny_keccak::{Hasher, Keccak}; +use crate::TREE_DEPTH; + /// Return the keccak256 digest of the preimage pub fn hash(preimage: impl AsRef<[u8]>) -> H256 { let mut output = [0u8; 32]; @@ -17,8 +19,19 @@ pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { hash(vec) } -/// Max number of leaves in a tree -pub(crate) fn max_leaves(n: usize) -> U256 { U256::from(2).pow(n.into()) - 1 } +/// Max number of leaves in a tree. Returns `None` if overflow occurred +/// (i.e. n > 32). +pub(crate) fn checked_max_leaves(n: usize) -> Option { + if n > TREE_DEPTH { + return None; + } + + Some(if n == 32 { + u32::MAX + } else { + 2u32.pow(n as u32) - 1 + }) +} /// Compute a root hash from a leaf and a Merkle proof. pub fn merkle_root_from_branch(leaf: H256, branch: &[H256], depth: usize, index: usize) -> H256 { From c412b927625e37da67c75734f705bcad00652e33 Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Wed, 14 Sep 2022 12:07:51 -0700 Subject: [PATCH 04/11] remove panic for branch_root method --- primitives/nomad/merkle/src/error.rs | 8 ++++---- primitives/nomad/merkle/src/lib.rs | 2 +- primitives/nomad/merkle/src/light.rs | 6 ++---- primitives/nomad/merkle/src/proof.rs | 4 ++-- primitives/nomad/merkle/src/test_utils.rs | 2 +- primitives/nomad/merkle/src/utils.rs | 23 ++++++++++++----------- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/primitives/nomad/merkle/src/error.rs b/primitives/nomad/merkle/src/error.rs index d54bcd085..acd3141c4 100644 --- a/primitives/nomad/merkle/src/error.rs +++ b/primitives/nomad/merkle/src/error.rs @@ -1,4 +1,4 @@ -use primitive_types::H256; +use sp_core::H256; /// Tree Errors #[derive(Debug, thiserror_no_std::Error, Clone, Copy)] @@ -29,7 +29,7 @@ pub enum TreeError { /// Incorrect Depth provided #[error("Incorrect Depth provided")] DepthTooSmall, - /// Integer overflow - #[error("Integer overflow occured")] - IntegerOverflow, + /// Depth provided too large + #[error("Provided tree depth exceeded 32")] + DepthTooLarge, } diff --git a/primitives/nomad/merkle/src/lib.rs b/primitives/nomad/merkle/src/lib.rs index d57fce53a..62d3e94a9 100644 --- a/primitives/nomad/merkle/src/lib.rs +++ b/primitives/nomad/merkle/src/lib.rs @@ -20,7 +20,7 @@ pub mod proof; #[cfg(test)] pub(crate) mod test_utils; -use primitive_types::H256; +use sp_core::H256; /// Tree depth pub const TREE_DEPTH: usize = 32; diff --git a/primitives/nomad/merkle/src/light.rs b/primitives/nomad/merkle/src/light.rs index 2641411aa..db2917855 100644 --- a/primitives/nomad/merkle/src/light.rs +++ b/primitives/nomad/merkle/src/light.rs @@ -1,6 +1,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::ensure; -use primitive_types::H256; +use sp_core::H256; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -34,9 +34,7 @@ impl Merkle for LightMerkle { type Proof = Proof; /// Return the maximum number of leaves in this tree - fn max_elements() -> Result { - super::utils::checked_max_leaves(N).ok_or(TreeError::IntegerOverflow) - } + fn max_elements() -> Result { super::utils::max_leaves(N) } fn count(&self) -> u32 { self.count } diff --git a/primitives/nomad/merkle/src/proof.rs b/primitives/nomad/merkle/src/proof.rs index ca2cb5cdb..6b82dea02 100644 --- a/primitives/nomad/merkle/src/proof.rs +++ b/primitives/nomad/merkle/src/proof.rs @@ -1,4 +1,4 @@ -use primitive_types::H256; +use sp_core::H256; use super::{merkle_root_from_branch, MerkleProof}; @@ -54,5 +54,5 @@ mod const_array_serde { impl MerkleProof for Proof { /// Calculate the merkle root produced by evaluating the proof - fn root(&self) -> H256 { merkle_root_from_branch(self.leaf, self.path.as_ref(), N, self.index) } + fn root(&self) -> H256 { merkle_root_from_branch(self.leaf, &self.path, self.index) } } diff --git a/primitives/nomad/merkle/src/test_utils.rs b/primitives/nomad/merkle/src/test_utils.rs index 6d953cd20..0192420c1 100644 --- a/primitives/nomad/merkle/src/test_utils.rs +++ b/primitives/nomad/merkle/src/test_utils.rs @@ -2,7 +2,7 @@ use std::{fs::File, io::Read}; -use primitive_types::H256; +use sp_core::H256; use crate::NomadProof; diff --git a/primitives/nomad/merkle/src/utils.rs b/primitives/nomad/merkle/src/utils.rs index 8f4cfdda1..d34ed6951 100644 --- a/primitives/nomad/merkle/src/utils.rs +++ b/primitives/nomad/merkle/src/utils.rs @@ -1,7 +1,8 @@ -use primitive_types::H256; +use frame_support::ensure; +use sp_core::H256; use tiny_keccak::{Hasher, Keccak}; -use crate::TREE_DEPTH; +use crate::{TreeError, TREE_DEPTH}; /// Return the keccak256 digest of the preimage pub fn hash(preimage: impl AsRef<[u8]>) -> H256 { @@ -21,12 +22,10 @@ pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { /// Max number of leaves in a tree. Returns `None` if overflow occurred /// (i.e. n > 32). -pub(crate) fn checked_max_leaves(n: usize) -> Option { - if n > TREE_DEPTH { - return None; - } +pub(crate) fn max_leaves(n: usize) -> Result { + ensure!(n <= TREE_DEPTH, TreeError::DepthTooLarge); - Some(if n == 32 { + Ok(if n == 32 { u32::MAX } else { 2u32.pow(n as u32) - 1 @@ -34,12 +33,14 @@ pub(crate) fn checked_max_leaves(n: usize) -> Option { } /// Compute a root hash from a leaf and a Merkle proof. -pub fn merkle_root_from_branch(leaf: H256, branch: &[H256], depth: usize, index: usize) -> H256 { - assert_eq!(branch.len(), depth, "proof length should equal depth"); - +pub fn merkle_root_from_branch( + leaf: H256, + branch: &[H256; N], + index: usize, +) -> H256 { let mut current = leaf; - for (i, next) in branch.iter().enumerate().take(depth) { + for (i, next) in branch.iter().enumerate().take(N) { let ith_bit = (index >> i) & 0x01; if ith_bit == 1 { current = hash_concat(next, current); From 645d8b074ff971678cde03273ec45b55971623d5 Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Wed, 14 Sep 2022 12:18:53 -0700 Subject: [PATCH 05/11] remove tiny keccak from merkle --- Cargo.lock | 1 - primitives/avail/src/header.rs | 6 ++++-- primitives/nomad/merkle/Cargo.toml | 1 - primitives/nomad/merkle/src/light.rs | 3 +-- primitives/nomad/merkle/src/utils.rs | 13 ++----------- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce3a1b1f1..9196acb2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4318,7 +4318,6 @@ dependencies = [ "sp-std", "static_assertions", "thiserror-no-std", - "tiny-keccak", ] [[package]] diff --git a/primitives/avail/src/header.rs b/primitives/avail/src/header.rs index 650be8392..d488c1bbc 100644 --- a/primitives/avail/src/header.rs +++ b/primitives/avail/src/header.rs @@ -4,7 +4,7 @@ use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_core::{RuntimeDebug, U256, H256}; +use sp_core::{RuntimeDebug, H256, U256}; use sp_runtime::{ traits::{ AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, MaybeFromStr, @@ -278,7 +278,9 @@ where fn data_root(&self) -> H256 { self.extrinsics_root.data_root.into() } - fn set_data_root(&mut self, data_root: H256) { self.extrinsics_root.data_root = data_root.into(); } + fn set_data_root(&mut self, data_root: H256) { + self.extrinsics_root.data_root = data_root.into(); + } fn data_lookup(&self) -> &DataLookup { &self.app_data_lookup } diff --git a/primitives/nomad/merkle/Cargo.toml b/primitives/nomad/merkle/Cargo.toml index f6ffd5bbe..9346e7e72 100644 --- a/primitives/nomad/merkle/Cargo.toml +++ b/primitives/nomad/merkle/Cargo.toml @@ -17,7 +17,6 @@ frame-support = { version = "4.0.0-dev", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info", "codec"] } -tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } thiserror-no-std = "2.0.2" static_assertions = "1.1.0" diff --git a/primitives/nomad/merkle/src/light.rs b/primitives/nomad/merkle/src/light.rs index db2917855..2b3da2f49 100644 --- a/primitives/nomad/merkle/src/light.rs +++ b/primitives/nomad/merkle/src/light.rs @@ -1,10 +1,9 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::ensure; -use sp_core::H256; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_core::RuntimeDebug; +use sp_core::{RuntimeDebug, H256}; use super::{ error::TreeError, utils::hash_concat, Merkle, MerkleProof, Proof, TREE_DEPTH, ZERO_HASHES, diff --git a/primitives/nomad/merkle/src/utils.rs b/primitives/nomad/merkle/src/utils.rs index d34ed6951..a3f892c51 100644 --- a/primitives/nomad/merkle/src/utils.rs +++ b/primitives/nomad/merkle/src/utils.rs @@ -1,23 +1,14 @@ use frame_support::ensure; use sp_core::H256; -use tiny_keccak::{Hasher, Keccak}; +use sp_runtime::traits::{Hash, Keccak256}; use crate::{TreeError, TREE_DEPTH}; -/// Return the keccak256 digest of the preimage -pub fn hash(preimage: impl AsRef<[u8]>) -> H256 { - let mut output = [0u8; 32]; - let mut hasher = Keccak::v256(); - hasher.update(preimage.as_ref()); - hasher.finalize(&mut output); - output.into() -} - /// Return the keccak256 disgest of the concatenation of the arguments pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { let mut vec = left.as_ref().to_vec(); vec.extend_from_slice(right.as_ref()); - hash(vec) + Keccak256::hash(vec.as_ref()) } /// Max number of leaves in a tree. Returns `None` if overflow occurred From ac3eb9bf637d1ddef54b9f1df4bd28824d4b6a02 Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Wed, 14 Sep 2022 12:23:31 -0700 Subject: [PATCH 06/11] address nomad base comments, removing unneeded methods --- primitives/nomad/nomad-base/src/lib.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/primitives/nomad/nomad-base/src/lib.rs b/primitives/nomad/nomad-base/src/lib.rs index 4203cf0c6..2a6dcfbd6 100644 --- a/primitives/nomad/nomad-base/src/lib.rs +++ b/primitives/nomad/nomad-base/src/lib.rs @@ -44,19 +44,7 @@ impl NomadBase { } } - pub fn state(&self) -> NomadState { self.state } - - pub fn local_domain(&self) -> u32 { self.local_domain } - - pub fn committed_root(&self) -> H256 { self.committed_root } - - pub fn updater(&self) -> H160 { self.updater } - - pub fn home_domain_hash(&self) -> H256 { home_domain_hash(self.local_domain()) } - - pub fn set_state(&mut self, new_state: NomadState) { self.state = new_state } - - pub fn set_updater(&mut self, new_updater: H160) { self.updater = new_updater } + pub fn home_domain_hash(&self) -> H256 { home_domain_hash(self.local_domain) } pub fn set_committed_root(&mut self, new_committed_root: H256) { self.committed_root = new_committed_root; From 0c4fbf409f7be265376286c862bbbe48601e1bed Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Thu, 15 Sep 2022 11:28:01 -0700 Subject: [PATCH 07/11] address comments on signature and nomad-core --- Cargo.lock | 1 + primitives/nomad/nomad-base/src/lib.rs | 2 +- primitives/nomad/nomad-core/Cargo.toml | 1 + .../nomad/nomad-core/src/nomad_message.rs | 20 ++++++------- primitives/nomad/nomad-core/src/test_utils.rs | 2 +- primitives/nomad/nomad-core/src/update.rs | 8 ++---- primitives/nomad/nomad-core/src/update_v2.rs | 8 ++---- primitives/nomad/nomad-core/src/utils.rs | 4 +-- primitives/nomad/signature/src/signature.rs | 28 ++++++++++--------- primitives/nomad/signature/src/utils.rs | 22 ++++----------- 10 files changed, 42 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9196acb2a..f14cc4411 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4638,6 +4638,7 @@ dependencies = [ "signature 0.1.0", "sp-core", "sp-io", + "sp-runtime", "sp-std", "tiny-keccak", ] diff --git a/primitives/nomad/nomad-base/src/lib.rs b/primitives/nomad/nomad-base/src/lib.rs index 2a6dcfbd6..270c42ab1 100644 --- a/primitives/nomad/nomad-base/src/lib.rs +++ b/primitives/nomad/nomad-base/src/lib.rs @@ -2,10 +2,10 @@ use frame_support::pallet_prelude::*; use nomad_core::{home_domain_hash, to_eth_signed_message_hash, NomadState, SignedUpdate, Update}; -use primitive_types::{H160, H256}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use signature::SignatureError; +use sp_core::{H160, H256}; #[cfg(feature = "testing")] pub mod testing; diff --git a/primitives/nomad/nomad-core/Cargo.toml b/primitives/nomad/nomad-core/Cargo.toml index 0c0109ac5..e54496125 100644 --- a/primitives/nomad/nomad-core/Cargo.toml +++ b/primitives/nomad/nomad-core/Cargo.toml @@ -12,6 +12,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-std = { version = "4.0.0-dev", default-features = false } sp-core = { version = "4.0.0-dev", default-features = false } sp-io = { version = "4.0.0-dev", default-features = false } +sp-runtime = { version = "4.0.0-dev", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } diff --git a/primitives/nomad/nomad-core/src/nomad_message.rs b/primitives/nomad/nomad-core/src/nomad_message.rs index c701ba6b5..b439782f4 100644 --- a/primitives/nomad/nomad-core/src/nomad_message.rs +++ b/primitives/nomad/nomad-core/src/nomad_message.rs @@ -1,16 +1,14 @@ use alloc::vec::Vec; use frame_support::pallet_prelude::*; -use primitive_types::H256; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; +use sp_core::H256; +use sp_runtime::traits::{Hash, Keccak256}; -use crate::utils::keccak256; +const NON_BODY_LENGTH: usize = 4 + 32 + 4 + 4 + 32; /// A full Nomad message #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct NomadMessage { +pub struct NomadMessage> { /// 4 SLIP-44 ID pub origin: u32, /// 32 Address in home convention @@ -22,13 +20,15 @@ pub struct NomadMessage { /// 32 Address in destination convention pub recipient: H256, /// 0+ Message contents - pub body: Vec, + pub body: BoundedVec, } -impl NomadMessage { +impl> NomadMessage { /// Serialize to a vec pub fn to_vec(&self) -> Vec { - let mut buf = Vec::::new(); + let size = NON_BODY_LENGTH + (S::get() as usize); + let mut buf = Vec::::with_capacity(size); + buf.extend_from_slice(&self.origin.to_be_bytes()); buf.extend_from_slice(&self.sender.as_ref()); buf.extend_from_slice(&self.nonce.to_be_bytes()); @@ -40,5 +40,5 @@ impl NomadMessage { } /// Get hash of message - pub fn hash(&self) -> H256 { keccak256(self.to_vec()).into() } + pub fn hash(&self) -> H256 { Keccak256::hash(&self.to_vec()).into() } } diff --git a/primitives/nomad/nomad-core/src/test_utils.rs b/primitives/nomad/nomad-core/src/test_utils.rs index 70e7bdbf4..aa56a4d90 100644 --- a/primitives/nomad/nomad-core/src/test_utils.rs +++ b/primitives/nomad/nomad-core/src/test_utils.rs @@ -1,7 +1,7 @@ use ethers_core::utils::hash_message; use ethers_signers::{LocalWallet, Signer}; -use primitive_types::{H160, H256}; use signature::Signature; +use sp_core::{H160, H256}; use crate::{ update_v2::{SignedUpdateV2, UpdateV2}, diff --git a/primitives/nomad/nomad-core/src/update.rs b/primitives/nomad/nomad-core/src/update.rs index 0625bfd40..500a6bd0b 100644 --- a/primitives/nomad/nomad-core/src/update.rs +++ b/primitives/nomad/nomad-core/src/update.rs @@ -1,8 +1,8 @@ use frame_support::pallet_prelude::*; -use primitive_types::{H160, H256}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use signature::{hash_message, Signature, SignatureError}; +use sp_core::{H160, H256}; use tiny_keccak::{Hasher, Keccak}; use crate::utils::home_domain_hash; @@ -51,14 +51,12 @@ impl SignedUpdate { /// Recover the Ethereum address of the signer pub fn recover(&self) -> Result { - Ok(self.signature.recover(self.update.prepended_hash())?) + self.signature.recover(self.update.prepended_hash()) } /// Check whether a message was signed by a specific address pub fn verify(&self, signer: H160) -> Result<(), SignatureError> { - Ok(self - .signature - .verify(self.update.prepended_hash(), signer)?) + self.signature.verify(self.update.prepended_hash(), signer) } } diff --git a/primitives/nomad/nomad-core/src/update_v2.rs b/primitives/nomad/nomad-core/src/update_v2.rs index 208a4ec67..ae109d2bd 100644 --- a/primitives/nomad/nomad-core/src/update_v2.rs +++ b/primitives/nomad/nomad-core/src/update_v2.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] use frame_support::pallet_prelude::*; -use primitive_types::{H160, H256}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use signature::{hash_message, Signature, SignatureError}; +use sp_core::{H160, H256}; use tiny_keccak::{Hasher, Keccak}; use crate::utils::home_domain_hash; @@ -46,14 +46,12 @@ pub struct SignedUpdateV2 { impl SignedUpdateV2 { /// Recover the Ethereum address of the signer pub fn recover(&self) -> Result { - Ok(self.signature.recover(self.update.prepended_hash())?) + self.signature.recover(self.update.prepended_hash()) } /// Check whether a message was signed by a specific address pub fn verify(&self, signer: H160) -> Result<(), SignatureError> { - Ok(self - .signature - .verify(self.update.prepended_hash(), signer)?) + self.signature.verify(self.update.prepended_hash(), signer) } } diff --git a/primitives/nomad/nomad-core/src/utils.rs b/primitives/nomad/nomad-core/src/utils.rs index afda25934..e22cb4e72 100644 --- a/primitives/nomad/nomad-core/src/utils.rs +++ b/primitives/nomad/nomad-core/src/utils.rs @@ -1,4 +1,4 @@ -use primitive_types::H256; +use sp_core::H256; use tiny_keccak::{Hasher, Keccak}; const NOMAD_PREFIX: &str = "NOMAD"; @@ -39,7 +39,5 @@ pub fn to_eth_signed_message_hash(hash: &H256) -> H256 { /// Destination and destination-specific nonce combined in single field ( /// (destination << 32) & nonce) pub fn destination_and_nonce(destination: u32, nonce: u32) -> u64 { - assert!(destination < u32::MAX); - assert!(nonce < u32::MAX); ((destination as u64) << 32) | nonce as u64 } diff --git a/primitives/nomad/signature/src/signature.rs b/primitives/nomad/signature/src/signature.rs index 2f00cacfa..7a87d7369 100644 --- a/primitives/nomad/signature/src/signature.rs +++ b/primitives/nomad/signature/src/signature.rs @@ -1,10 +1,10 @@ -// Code adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/api/accounts.rs +// Code adapted from: https://github.com/gakonst/ethers-rs/blob/master/ethers-core/src/types/signature.rs use alloc::{borrow::ToOwned, string::String, vec::Vec}; use core::{convert::TryFrom, fmt, str::FromStr}; use elliptic_curve::{consts::U32, sec1::ToEncodedPoint}; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, sp_runtime::traits::Keccak256}; use generic_array::GenericArray; use k256::{ ecdsa::{ @@ -13,9 +13,9 @@ use k256::{ }, PublicKey as K256PublicKey, }; -use primitive_types::{H160, H256, U256}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; +use sp_core::{Hasher, H160, H256, U256}; use thiserror::Error; use crate::utils::hash_message; @@ -84,9 +84,10 @@ impl Signature { { let address = address.into(); let recovered = self.recover(message)?; - if recovered != address { - return Err(SignatureError::VerificationError(address, recovered)); - } + ensure!( + recovered == address, + SignatureError::VerificationError(address, recovered) + ); Ok(()) } @@ -113,7 +114,7 @@ impl Signature { let public_key = public_key.to_encoded_point(/* compress = */ false); let public_key = public_key.as_bytes(); debug_assert_eq!(public_key[0], 0x04); - let hash = crate::utils::keccak256(&public_key[1..]); + let hash = Keccak256::hash(&public_key[1..]); Ok(Address::from_slice(&hash[12..])) } @@ -188,14 +189,15 @@ impl FromStr for Signature { impl From<&Signature> for [u8; 65] { fn from(src: &Signature) -> [u8; 65] { let mut sig = [0u8; 65]; - let mut r_bytes = [0u8; 32]; - let mut s_bytes = [0u8; 32]; - src.r.to_big_endian(&mut r_bytes); - src.s.to_big_endian(&mut s_bytes); - sig[..32].copy_from_slice(&r_bytes); - sig[32..64].copy_from_slice(&s_bytes); + src.r.to_big_endian(&mut sig); + src.s.to_big_endian(&mut sig); // TODO: What if we try to serialize a signature where // the `v` is not normalized? + + // The u64 to u8 cast is safe because `sig.v` can only ever be 27 or 28 + // here. Regarding EIP-155, the modification to `v` happens during tx + // creation only _after_ the transaction is signed using + // `ethers_signers::to_eip155_v`. sig[64] = src.v as u8; sig } diff --git a/primitives/nomad/signature/src/utils.rs b/primitives/nomad/signature/src/utils.rs index eac8cd799..ce4e9ebf0 100644 --- a/primitives/nomad/signature/src/utils.rs +++ b/primitives/nomad/signature/src/utils.rs @@ -1,5 +1,5 @@ -//! Various utilities for manipulating Ethereum related dat -use primitive_types::H256; +//! Various utilities for manipulating Ethereum related data +use sp_core::H256; use tiny_keccak::{Hasher, Keccak}; const PREFIX: &str = "\x19Ethereum Signed Message:\n"; @@ -14,22 +14,12 @@ where S: AsRef<[u8]>, { let message = message.as_ref(); + let eth_message = format!("{}{}", PREFIX, message.len()).into_bytes(); - let mut eth_message = format!("{}{}", PREFIX, message.len()).into_bytes(); - eth_message.extend_from_slice(message); - - keccak256(ð_message).into() -} - -/// Compute the Keccak-256 hash of input bytes. -// TODO: Add Solidity Keccak256 packing support -pub fn keccak256(bytes: S) -> [u8; 32] -where - S: AsRef<[u8]>, -{ let mut output = [0u8; 32]; let mut hasher = Keccak::v256(); - hasher.update(bytes.as_ref()); + hasher.update(eth_message.as_ref()); + hasher.update(message); hasher.finalize(&mut output); - output + output.into() } From a18052b1e0a62125e7bed5f0af1848fa42264550 Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Thu, 15 Sep 2022 11:46:57 -0700 Subject: [PATCH 08/11] add tiny keccak back to merkle and use to avoid extra allocation in left/right hash --- Cargo.lock | 1 + primitives/nomad/merkle/Cargo.toml | 1 + primitives/nomad/merkle/src/utils.rs | 11 +++++++---- primitives/nomad/signature/src/signature.rs | 8 ++++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f14cc4411..2cc67b8c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4318,6 +4318,7 @@ dependencies = [ "sp-std", "static_assertions", "thiserror-no-std", + "tiny-keccak", ] [[package]] diff --git a/primitives/nomad/merkle/Cargo.toml b/primitives/nomad/merkle/Cargo.toml index 9346e7e72..398b8e864 100644 --- a/primitives/nomad/merkle/Cargo.toml +++ b/primitives/nomad/merkle/Cargo.toml @@ -15,6 +15,7 @@ sp-io = { version = "4.0.0-dev", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info", "codec"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } diff --git a/primitives/nomad/merkle/src/utils.rs b/primitives/nomad/merkle/src/utils.rs index a3f892c51..7f29ca6dd 100644 --- a/primitives/nomad/merkle/src/utils.rs +++ b/primitives/nomad/merkle/src/utils.rs @@ -1,14 +1,17 @@ use frame_support::ensure; use sp_core::H256; -use sp_runtime::traits::{Hash, Keccak256}; +use tiny_keccak::{Hasher, Keccak}; use crate::{TreeError, TREE_DEPTH}; /// Return the keccak256 disgest of the concatenation of the arguments pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { - let mut vec = left.as_ref().to_vec(); - vec.extend_from_slice(right.as_ref()); - Keccak256::hash(vec.as_ref()) + let mut output = [0u8; 32]; + let mut hasher = Keccak::v256(); + hasher.update(left.as_ref()); + hasher.update(right.as_ref()); + hasher.finalize(&mut output); + output.into() } /// Max number of leaves in a tree. Returns `None` if overflow occurred diff --git a/primitives/nomad/signature/src/signature.rs b/primitives/nomad/signature/src/signature.rs index 7a87d7369..d942788ff 100644 --- a/primitives/nomad/signature/src/signature.rs +++ b/primitives/nomad/signature/src/signature.rs @@ -194,10 +194,10 @@ impl From<&Signature> for [u8; 65] { // TODO: What if we try to serialize a signature where // the `v` is not normalized? - // The u64 to u8 cast is safe because `sig.v` can only ever be 27 or 28 - // here. Regarding EIP-155, the modification to `v` happens during tx - // creation only _after_ the transaction is signed using - // `ethers_signers::to_eip155_v`. + // The u64 to u8 cast is safe because `sig.v` can only ever be 27 or 28 + // here. Regarding EIP-155, the modification to `v` happens during tx + // creation only _after_ the transaction is signed using + // `ethers_signers::to_eip155_v`. sig[64] = src.v as u8; sig } From bf6f27c3ddf8a6ee801ca1d65420080f5c5d3aea Mon Sep 17 00:00:00 2001 From: Luke Tchang Date: Thu, 15 Sep 2022 17:47:26 -0700 Subject: [PATCH 09/11] fix bug addressing signature From optimization --- primitives/nomad/signature/src/signature.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/nomad/signature/src/signature.rs b/primitives/nomad/signature/src/signature.rs index d942788ff..c1aa4b363 100644 --- a/primitives/nomad/signature/src/signature.rs +++ b/primitives/nomad/signature/src/signature.rs @@ -189,8 +189,8 @@ impl FromStr for Signature { impl From<&Signature> for [u8; 65] { fn from(src: &Signature) -> [u8; 65] { let mut sig = [0u8; 65]; - src.r.to_big_endian(&mut sig); - src.s.to_big_endian(&mut sig); + src.r.to_big_endian(&mut sig[..32]); + src.s.to_big_endian(&mut sig[32..64]); // TODO: What if we try to serialize a signature where // the `v` is not normalized? From 75c6e80d729e9029526038491d4a6bc5f7208074 Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 16 Sep 2022 14:22:45 +0200 Subject: [PATCH 10/11] Add static assertion & remove `testing` feature --- primitives/nomad/merkle/src/lib.rs | 13 +++--- primitives/nomad/merkle/src/light.rs | 43 ++++++++++++++++---- primitives/nomad/merkle/src/utils.rs | 15 ------- primitives/nomad/nomad-base/Cargo.toml | 25 +++--------- primitives/nomad/nomad-base/src/lib.rs | 5 +-- primitives/nomad/nomad-base/src/testing.rs | 1 + primitives/nomad/nomad-core/Cargo.toml | 33 ++++----------- primitives/nomad/nomad-core/src/lib.rs | 2 +- primitives/nomad/nomad-core/src/update.rs | 4 +- primitives/nomad/nomad-core/src/update_v2.rs | 4 +- primitives/nomad/signature/Cargo.toml | 20 +++------ primitives/nomad/signature/src/signature.rs | 2 +- 12 files changed, 66 insertions(+), 101 deletions(-) diff --git a/primitives/nomad/merkle/src/lib.rs b/primitives/nomad/merkle/src/lib.rs index 62d3e94a9..1f2b2d7cb 100644 --- a/primitives/nomad/merkle/src/lib.rs +++ b/primitives/nomad/merkle/src/lib.rs @@ -20,6 +20,7 @@ pub mod proof; #[cfg(test)] pub(crate) mod test_utils; +use frame_support::ensure; use sp_core::H256; /// Tree depth @@ -29,7 +30,7 @@ pub type NomadLightMerkle = light::LightMerkle; /// A Nomad protocol standard-depth proof pub type NomadProof = proof::Proof; -pub use error::*; +pub use error::{TreeError, VerifyingError, VerifyingError::VerificationFailed}; pub use light::*; pub use proof::*; pub use utils::*; @@ -57,7 +58,7 @@ pub trait Merkle: core::fmt::Debug + Default { type Proof: MerkleProof; /// The maximum number of elements the tree can ingest - fn max_elements() -> Result; + fn max_elements() -> u32; /// The number of elements currently in the tree fn count(&self) -> u32; @@ -75,10 +76,8 @@ pub trait Merkle: core::fmt::Debug + Default { fn verify(&self, proof: &Self::Proof) -> Result<(), VerifyingError> { let actual = proof.root(); let expected = self.root(); - if expected == actual { - Ok(()) - } else { - Err(VerifyingError::VerificationFailed { expected, actual }) - } + ensure!(expected == actual, VerificationFailed { expected, actual }); + + Ok(()) } } diff --git a/primitives/nomad/merkle/src/light.rs b/primitives/nomad/merkle/src/light.rs index 2b3da2f49..7a80d8157 100644 --- a/primitives/nomad/merkle/src/light.rs +++ b/primitives/nomad/merkle/src/light.rs @@ -9,6 +9,20 @@ use super::{ error::TreeError, utils::hash_concat, Merkle, MerkleProof, Proof, TREE_DEPTH, ZERO_HASHES, }; +/// Const assertions at `LightMerkle` struct. +struct AssertLightMerkleN; +impl AssertLightMerkleN { + /// `N` must be less or equal to `TREE_DEPTH`. + pub const N_LESS_EQ_TREE_DEPTH: usize = TREE_DEPTH - N; +} + +/// Verify at compilation time that `N <= TREE_DEPTH` +#[inline] +#[allow(path_statements)] +const fn const_assert_n_is_valid() { + AssertLightMerkleN::::N_LESS_EQ_TREE_DEPTH; +} + /// An incremental merkle tree, modeled on the eth2 deposit contract #[derive(Clone, Copy, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -20,6 +34,7 @@ pub struct LightMerkle { impl Default for LightMerkle { fn default() -> Self { + const_assert_n_is_valid::(); let mut branch: [H256; N] = [Default::default(); N]; branch .iter_mut() @@ -33,7 +48,10 @@ impl Merkle for LightMerkle { type Proof = Proof; /// Return the maximum number of leaves in this tree - fn max_elements() -> Result { super::utils::max_leaves(N) } + fn max_elements() -> u32 { + const_assert_n_is_valid::(); + 2u32.saturating_pow(N as u32) + } fn count(&self) -> u32 { self.count } @@ -56,10 +74,7 @@ impl Merkle for LightMerkle { fn depth(&self) -> usize { N } fn ingest(&mut self, element: H256) -> Result { - ensure!( - Self::max_elements()? > self.count, - TreeError::MerkleTreeFull - ); + ensure!(Self::max_elements() > self.count, TreeError::MerkleTreeFull); let mut node = element; @@ -79,6 +94,8 @@ impl Merkle for LightMerkle { } impl LightMerkle { + pub const N_LESS_THAN_TREE_DEPTH_ASSERT: usize = TREE_DEPTH - N; + /// Instantiate a new tree with a known depth and a starting leaf-set pub fn from_leaves(leaves: &[H256]) -> Result { let mut tree = Self::default(); @@ -119,9 +136,7 @@ mod arrays { } s.end() } - struct ArrayVisitor(PhantomData); - impl<'de, T, const N: usize> Visitor<'de> for ArrayVisitor where T: Deserialize<'de>, @@ -198,4 +213,18 @@ mod test { } } } + + #[test] + fn it_n_less_than_max_tree_depth() { + const TREE_DEPTH_MINUS_ONE: usize = TREE_DEPTH - 1; + + let _ = LightMerkle::<0>::default(); + let _ = LightMerkle::<1>::default(); + let _ = LightMerkle::::default(); + let _ = LightMerkle::::default(); + + // Following code does not compile due to static asserts. + // const TREE_DEPTH_PLUS_ONE :usize = TREE_DEPTH +1; + // let _ = LightMerkle::::default(); + } } diff --git a/primitives/nomad/merkle/src/utils.rs b/primitives/nomad/merkle/src/utils.rs index 7f29ca6dd..66ff9967a 100644 --- a/primitives/nomad/merkle/src/utils.rs +++ b/primitives/nomad/merkle/src/utils.rs @@ -1,9 +1,6 @@ -use frame_support::ensure; use sp_core::H256; use tiny_keccak::{Hasher, Keccak}; -use crate::{TreeError, TREE_DEPTH}; - /// Return the keccak256 disgest of the concatenation of the arguments pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { let mut output = [0u8; 32]; @@ -14,18 +11,6 @@ pub fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { output.into() } -/// Max number of leaves in a tree. Returns `None` if overflow occurred -/// (i.e. n > 32). -pub(crate) fn max_leaves(n: usize) -> Result { - ensure!(n <= TREE_DEPTH, TreeError::DepthTooLarge); - - Ok(if n == 32 { - u32::MAX - } else { - 2u32.pow(n as u32) - 1 - }) -} - /// Compute a root hash from a leaf and a Merkle proof. pub fn merkle_root_from_branch( leaf: H256, diff --git a/primitives/nomad/nomad-base/Cargo.toml b/primitives/nomad/nomad-base/Cargo.toml index aa216399b..5d88f05b2 100644 --- a/primitives/nomad/nomad-base/Cargo.toml +++ b/primitives/nomad/nomad-base/Cargo.toml @@ -20,22 +20,12 @@ tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak signature = { path = "../signature", default-features = false } nomad-core = { path = "../nomad-core", default-features = false } +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } -[dependencies.serde] -version = "1.0" -default-features = false -optional = true -features = ["derive"] +[dev-dependencies] +ethers-signers = "0.13.0" +once_cell = "1.8.0" -[dependencies.ethers-signers] -version = "0.13.0" -default-features = false -optional = true - -[dependencies.once_cell] -version = "1.8.0" -default-features = false -optional = true [features] default = ["std"] @@ -47,9 +37,4 @@ std = [ "frame-support/std", "nomad-core/std" ] -testing = [ - "ethers-signers", - "once_cell", - "nomad-core/testing", - "signature/testing", -] \ No newline at end of file + diff --git a/primitives/nomad/nomad-base/src/lib.rs b/primitives/nomad/nomad-base/src/lib.rs index 270c42ab1..51d8cdef2 100644 --- a/primitives/nomad/nomad-base/src/lib.rs +++ b/primitives/nomad/nomad-base/src/lib.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use signature::SignatureError; use sp_core::{H160, H256}; -#[cfg(feature = "testing")] +#[cfg(test)] pub mod testing; #[derive(Clone, Copy, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -74,11 +74,9 @@ mod test { use nomad_core::test_utils::Updater; use super::*; - #[cfg(feature = "testing")] use crate::testing::{FAKE_UPDATER, TEST_NOMAD_BASE, TEST_UPDATER, TEST_UPDATER_PRIVKEY}; #[test] - #[cfg(feature = "testing")] fn it_accepts_valid_signature() { let valid_signed = TEST_UPDATER.sign_update(H256::repeat_byte(0), H256::repeat_byte(1)); assert!( @@ -88,7 +86,6 @@ mod test { } #[test] - #[cfg(feature = "testing")] fn it_rejects_invalid_signature() { let invalid_signed = FAKE_UPDATER.sign_update(H256::repeat_byte(0), H256::repeat_byte(1)); assert!( diff --git a/primitives/nomad/nomad-base/src/testing.rs b/primitives/nomad/nomad-base/src/testing.rs index 1aa8ee0dc..c451c9ea0 100644 --- a/primitives/nomad/nomad-base/src/testing.rs +++ b/primitives/nomad/nomad-base/src/testing.rs @@ -1,3 +1,4 @@ +#[cfg(test)] use ethers_signers::LocalWallet; use nomad_core::test_utils::Updater; use once_cell::sync::Lazy; diff --git a/primitives/nomad/nomad-core/Cargo.toml b/primitives/nomad/nomad-core/Cargo.toml index e54496125..828a52e1d 100644 --- a/primitives/nomad/nomad-core/Cargo.toml +++ b/primitives/nomad/nomad-core/Cargo.toml @@ -21,40 +21,23 @@ tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak signature = { path = "../signature", default-features = false } getrandom = { version = "0.2", default-features = false, features = ["js"] } -[dependencies.serde] -version = "1.0" -default-features = false -optional = true -features = ["derive"] +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } +ethers-core = { version = "0.13.0", optional = true } +ethers-signers = { version = "0.13.0", optional = true } -[dependencies.ethers-signers] -version = "0.13.0" -default-features = false -optional = true - -[dependencies.ethers-core] -version = "0.13.0" -default-features = false -optional = true - -[dependencies.async-trait] -version = "0.1.42" -default-features = false -optional = true +[dev-dependencies] +async-trait = "0.1.42" [features] default = ["std"] std = [ "serde", + "ethers-core", + "ethers-signers", "primitive-types/serde", "signature/std", "codec/std", "scale-info/std", "frame-support/std", ] -testing = [ - "ethers-signers", - "ethers-core", - "async-trait", - "signature/testing" -] \ No newline at end of file + diff --git a/primitives/nomad/nomad-core/src/lib.rs b/primitives/nomad/nomad-core/src/lib.rs index a4e8026d1..2eaca1be4 100644 --- a/primitives/nomad/nomad-core/src/lib.rs +++ b/primitives/nomad/nomad-core/src/lib.rs @@ -19,5 +19,5 @@ pub use typed_message::*; mod utils; pub use utils::*; -#[cfg(feature = "testing")] +#[cfg(feature = "std")] pub mod test_utils; diff --git a/primitives/nomad/nomad-core/src/update.rs b/primitives/nomad/nomad-core/src/update.rs index 500a6bd0b..dda52a315 100644 --- a/primitives/nomad/nomad-core/src/update.rs +++ b/primitives/nomad/nomad-core/src/update.rs @@ -62,15 +62,13 @@ impl SignedUpdate { #[cfg(test)] mod tests { - use super::*; - #[cfg(feature = "testing")] + use super::H256; use crate::test_utils::Updater; pub const TEST_UPDATER_PRIVKEY: &str = "1111111111111111111111111111111111111111111111111111111111111111"; #[test] - #[cfg(feature = "testing")] fn recover_valid_update() { use ethers_signers::{LocalWallet, Signer}; diff --git a/primitives/nomad/nomad-core/src/update_v2.rs b/primitives/nomad/nomad-core/src/update_v2.rs index ae109d2bd..de8c57e59 100644 --- a/primitives/nomad/nomad-core/src/update_v2.rs +++ b/primitives/nomad/nomad-core/src/update_v2.rs @@ -57,15 +57,13 @@ impl SignedUpdateV2 { #[cfg(test)] mod tests { - use super::*; - #[cfg(feature = "testing")] + use super::H256; use crate::test_utils::Updater; pub const TEST_UPDATER_PRIVKEY: &str = "1111111111111111111111111111111111111111111111111111111111111111"; #[test] - #[cfg(feature = "testing")] fn recover_valid_update_v2() { use ethers_signers::{LocalWallet, Signer}; diff --git a/primitives/nomad/signature/Cargo.toml b/primitives/nomad/signature/Cargo.toml index bc5159221..6dbaa8d25 100644 --- a/primitives/nomad/signature/Cargo.toml +++ b/primitives/nomad/signature/Cargo.toml @@ -41,21 +41,11 @@ thiserror-no-std = "2.0.1" hex = { version = "0.4.3", default-features = false } once_cell = { version = "1.12.0", optional = true } -[dependencies.serde] -version = "1.0" -default-features = false -optional = true -features = ["derive"] +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } +ethers-core = { version = "0.13.0", optional = true } -[dependencies.ethers-core] -version = "0.13.0" -default-features = false -optional = true - -[dependencies.byte-slice-cast] -version = "1.2.1" -default-features = false -optional = true +[dev-dependencies] +byte-slice-cast = "1.2.1" [features] default = ["std"] @@ -65,5 +55,5 @@ std = [ "codec/std", "scale-info/std", "frame-support/std", + "ethers-core" ] -testing = ["ethers-core", "byte-slice-cast"] \ No newline at end of file diff --git a/primitives/nomad/signature/src/signature.rs b/primitives/nomad/signature/src/signature.rs index c1aa4b363..b2e28d892 100644 --- a/primitives/nomad/signature/src/signature.rs +++ b/primitives/nomad/signature/src/signature.rs @@ -239,8 +239,8 @@ impl From for RecoveryMessage { fn from(hash: H256) -> Self { RecoveryMessage::Hash(hash) } } +#[cfg(feature = "std")] // Want to convert ethers signature into our no-std version in tests -#[cfg(feature = "testing")] impl From for Signature { fn from(sig: ethers_core::types::Signature) -> Self { // ethers-core 0.13.0 uses primitive types 0.11.1, sp-core 4.0.0-dev From a38bd88fa93a35e0893c68aec85201a15c8341ef Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 16 Sep 2022 14:35:30 +0200 Subject: [PATCH 11/11] Remove unused constant --- primitives/nomad/merkle/src/light.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/primitives/nomad/merkle/src/light.rs b/primitives/nomad/merkle/src/light.rs index 7a80d8157..bc074dbe6 100644 --- a/primitives/nomad/merkle/src/light.rs +++ b/primitives/nomad/merkle/src/light.rs @@ -94,8 +94,6 @@ impl Merkle for LightMerkle { } impl LightMerkle { - pub const N_LESS_THAN_TREE_DEPTH_ASSERT: usize = TREE_DEPTH - N; - /// Instantiate a new tree with a known depth and a starting leaf-set pub fn from_leaves(leaves: &[H256]) -> Result { let mut tree = Self::default();