mirror of
https://github.com/vacp2p/zerokit.git
synced 2026-01-10 06:58:03 -05:00
Enable parallel execution for Merkle Tree (#306)
This commit is contained in:
221
Cargo.lock
generated
221
Cargo.lock
generated
@@ -4,29 +4,29 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy 0.7.35",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -112,9 +112,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "ark-bn254"
|
||||
@@ -159,7 +159,7 @@ checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -175,7 +175,7 @@ dependencies = [
|
||||
"ark-std 0.5.0",
|
||||
"educe",
|
||||
"fnv",
|
||||
"hashbrown 0.15.2",
|
||||
"hashbrown 0.15.3",
|
||||
"itertools 0.13.0",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
@@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -308,7 +308,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -339,7 +339,7 @@ dependencies = [
|
||||
"ark-std 0.5.0",
|
||||
"educe",
|
||||
"fnv",
|
||||
"hashbrown 0.15.2",
|
||||
"hashbrown 0.15.3",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
@@ -415,7 +415,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -480,13 +480,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "auto_impl"
|
||||
version = "1.2.1"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73"
|
||||
checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -497,17 +497,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.71"
|
||||
version = "0.3.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -584,9 +584,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.17"
|
||||
version = "1.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -638,9 +638,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.35"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -648,9 +648,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.35"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -667,7 +667,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -687,9 +687,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5"
|
||||
checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"color-spantrace",
|
||||
@@ -702,9 +702,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
|
||||
checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
@@ -901,7 +901,7 @@ dependencies = [
|
||||
"enum-ordinalize",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -927,7 +927,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1023,9 +1023,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -1036,9 +1036,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -1048,15 +1048,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
|
||||
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
@@ -1070,9 +1070,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
]
|
||||
@@ -1121,7 +1121,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1142,12 +1142,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
"hashbrown 0.15.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1225,15 +1225,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.11"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
||||
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
@@ -1287,11 +1287,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1302,8 +1302,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1327,9 +1325,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -1354,9 +1352,9 @@ checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||
checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
|
||||
[[package]]
|
||||
name = "parity-scale-codec"
|
||||
@@ -1383,7 +1381,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1468,7 +1466,7 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy 0.8.24",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1493,9 +1491,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1536,7 +1534,7 @@ dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1573,13 +1571,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"zerocopy 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1608,7 +1605,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1617,7 +1614,7 @@ version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.2",
|
||||
"getrandom 0.3.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1715,7 +1712,6 @@ dependencies = [
|
||||
"ruint",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sled",
|
||||
"thiserror",
|
||||
"tiny-keccak",
|
||||
"zerokit_utils",
|
||||
@@ -1725,7 +1721,7 @@ dependencies = [
|
||||
name = "rln-cli"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"clap 4.5.35",
|
||||
"clap 4.5.38",
|
||||
"clap_derive",
|
||||
"color-eyre",
|
||||
"rln",
|
||||
@@ -1739,7 +1735,7 @@ name = "rln-wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.2.16",
|
||||
"js-sys",
|
||||
"num-bigint",
|
||||
"rln",
|
||||
@@ -1782,7 +1778,7 @@ dependencies = [
|
||||
"primitive-types",
|
||||
"proptest",
|
||||
"rand 0.8.5",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"rlp",
|
||||
"ruint-macro",
|
||||
"serde",
|
||||
@@ -1905,7 +1901,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1922,9 +1918,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
@@ -1964,9 +1960,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
@@ -1999,9 +1995,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2037,7 +2033,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2071,17 +2067,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.24"
|
||||
version = "0.22.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||
dependencies = [
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
@@ -2105,7 +2101,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2264,7 +2260,7 @@ dependencies = [
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -2299,7 +2295,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -2346,7 +2342,7 @@ checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2476,9 +2472,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -2503,42 +2499,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.24",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2558,7 +2534,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2574,6 +2550,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rayon",
|
||||
"serde",
|
||||
"sled",
|
||||
"tiny-keccak",
|
||||
|
||||
@@ -13,11 +13,11 @@ path = "src/examples/stateless.rs"
|
||||
required-features = ["stateless"]
|
||||
|
||||
[dependencies]
|
||||
rln = { path = "../rln", default-features = false }
|
||||
rln = { path = "../rln", default-features = true }
|
||||
zerokit_utils = { path = "../utils" }
|
||||
clap = { version = "4.5.35", features = ["cargo", "derive", "env"] }
|
||||
clap = { version = "4.5.38", features = ["cargo", "derive", "env"] }
|
||||
clap_derive = { version = "4.5.32" }
|
||||
color-eyre = "0.6.3"
|
||||
color-eyre = "0.6.4"
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@ required-features = ["stateless"]
|
||||
|
||||
[dependencies]
|
||||
rln = { path = "../rln", default-features = false }
|
||||
num-bigint = { version = "0.4.6", default-features = false, features = [
|
||||
"rand",
|
||||
"serde",
|
||||
] }
|
||||
num-bigint = { version = "0.4.6", default-features = false }
|
||||
js-sys = "0.3.77"
|
||||
wasm-bindgen = "0.2.100"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
@@ -27,7 +24,7 @@ console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
zerokit_utils = { path = "../utils" }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
getrandom = { version = "0.2.15", features = ["js"] }
|
||||
getrandom = { version = "0.2.16", features = ["js"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0"
|
||||
|
||||
@@ -40,16 +40,13 @@ ark-serialize = { version = "0.5.0", default-features = false, features = [
|
||||
] }
|
||||
|
||||
# error handling
|
||||
color-eyre = "0.6.3"
|
||||
color-eyre = "0.6.4"
|
||||
thiserror = "2.0.12"
|
||||
|
||||
# utilities
|
||||
byteorder = "1.5.0"
|
||||
cfg-if = "1.0"
|
||||
num-bigint = { version = "0.4.6", default-features = false, features = [
|
||||
"rand",
|
||||
"std",
|
||||
] }
|
||||
num-bigint = { version = "0.4.6", default-features = false, features = ["std"] }
|
||||
num-traits = "0.2.19"
|
||||
once_cell = "1.21.3"
|
||||
lazy_static = "1.5.0"
|
||||
@@ -67,7 +64,6 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
document-features = { version = "0.2.11", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
sled = "0.34.7"
|
||||
criterion = { version = "0.4.0", features = ["html_reports"] }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -26,12 +26,6 @@ pub fn pmtree_benchmark(c: &mut Criterion) {
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("Pmtree::compute_root", |b| {
|
||||
b.iter(|| {
|
||||
tree.compute_root().unwrap();
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("Pmtree::get", |b| {
|
||||
b.iter(|| {
|
||||
tree.get(0).unwrap();
|
||||
|
||||
@@ -168,10 +168,6 @@ impl ZerokitMerkleTree for PmTree {
|
||||
self.tree.root()
|
||||
}
|
||||
|
||||
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
|
||||
Ok(self.tree.root())
|
||||
}
|
||||
|
||||
fn set(&mut self, index: usize, leaf: FrOf<Self::Hasher>) -> Result<()> {
|
||||
self.tree
|
||||
.set(index, leaf)
|
||||
|
||||
@@ -15,15 +15,14 @@ bench = false
|
||||
ark-ff = { version = "0.5.0", default-features = false, features = [
|
||||
"parallel",
|
||||
] }
|
||||
num-bigint = { version = "0.4.6", default-features = false, features = [
|
||||
"rand",
|
||||
] }
|
||||
color-eyre = "0.6.3"
|
||||
num-bigint = { version = "0.4.6", default-features = false }
|
||||
color-eyre = "0.6.4"
|
||||
pmtree = { package = "vacp2p_pmtree", version = "2.0.2", optional = true }
|
||||
sled = "0.34.7"
|
||||
serde = "1.0"
|
||||
lazy_static = "1.5.0"
|
||||
hex = "0.4"
|
||||
hex = "0.4.3"
|
||||
rayon = "1.7.0"
|
||||
|
||||
[dev-dependencies]
|
||||
ark-bn254 = { version = "0.5.0", features = ["std"] }
|
||||
|
||||
@@ -20,20 +20,23 @@ The crate supports two interchangeable Merkle tree implementations:
|
||||
- **OptimalMerkleTree**
|
||||
- Only stores nodes used to prove accumulation of set leaves
|
||||
|
||||
Both OptimalMerkleTree and FullMerkleTree use [Rayon](https://crates.io/crates/rayon) internally to speed up computation through data parallelism. This provides significant performance improvements, especially during large Merkle tree updates.
|
||||
|
||||
### Implementation notes
|
||||
|
||||
Glossary:
|
||||
|
||||
* depth: level of leaves if we count from levels from 0
|
||||
* number of levels: depth + 1
|
||||
* capacity (== number of leaves) -- 1 << depth
|
||||
* total number of nodes: 1 << (depth + 1)) - 1
|
||||
- depth: level of leaves if we count from levels from 0
|
||||
- number of levels: depth + 1
|
||||
- capacity (number of leaves): 1 << depth
|
||||
- total number of nodes: 1 << (depth + 1) - 1
|
||||
|
||||
So for instance:
|
||||
* depth: 3
|
||||
* number of levels: 4
|
||||
* capacity (number of leaves): 8
|
||||
* total number of nodes: 15
|
||||
|
||||
- depth: 3
|
||||
- number of levels: 4
|
||||
- capacity (number of leaves): 8
|
||||
- total number of nodes: 15
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@@ -53,7 +56,6 @@ flowchart TD
|
||||
N6 -->|Leaf| L8
|
||||
```
|
||||
|
||||
|
||||
## Poseidon Hash Implementation
|
||||
|
||||
This crate provides an implementation to compute the Poseidon hash round constants and MDS matrices:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use hex_literal::hex;
|
||||
use lazy_static::lazy_static;
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
use tiny_keccak::{Hasher as _, Keccak};
|
||||
@@ -47,55 +46,78 @@ impl FromStr for TestFr {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref LEAVES: [TestFr; 4] = [
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000001"),
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000002"),
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000003"),
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000004"),
|
||||
]
|
||||
.map(TestFr);
|
||||
static ref LEAVES: Vec<TestFr> = {
|
||||
let mut leaves = Vec::with_capacity(1 << 20);
|
||||
for i in 0..(1 << 20) {
|
||||
let mut bytes = [0u8; 32];
|
||||
bytes[28..].copy_from_slice(&(i as u32).to_be_bytes());
|
||||
leaves.push(TestFr(bytes));
|
||||
}
|
||||
leaves
|
||||
};
|
||||
static ref INDICES: Vec<usize> = (0..(1 << 20)).collect();
|
||||
}
|
||||
|
||||
const NOF_LEAVES: usize = 8192;
|
||||
|
||||
pub fn optimal_merkle_tree_benchmark(c: &mut Criterion) {
|
||||
let mut tree =
|
||||
OptimalMerkleTree::<Keccak256>::new(2, TestFr([0; 32]), OptimalMerkleConfig::default())
|
||||
OptimalMerkleTree::<Keccak256>::new(20, TestFr([0; 32]), OptimalMerkleConfig::default())
|
||||
.unwrap();
|
||||
|
||||
for i in 0..NOF_LEAVES {
|
||||
tree.set(i, LEAVES[i % LEAVES.len()]).unwrap();
|
||||
}
|
||||
|
||||
c.bench_function("OptimalMerkleTree::set", |b| {
|
||||
let mut index = NOF_LEAVES;
|
||||
b.iter(|| {
|
||||
tree.set(0, LEAVES[0]).unwrap();
|
||||
tree.set(index % (1 << 20), LEAVES[index % LEAVES.len()])
|
||||
.unwrap();
|
||||
index = (index + 1) % (1 << 20);
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("OptimalMerkleTree::delete", |b| {
|
||||
let mut index = 0;
|
||||
b.iter(|| {
|
||||
tree.delete(0).unwrap();
|
||||
tree.delete(index % NOF_LEAVES).unwrap();
|
||||
tree.set(index % NOF_LEAVES, LEAVES[index % LEAVES.len()])
|
||||
.unwrap();
|
||||
index = (index + 1) % NOF_LEAVES;
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("OptimalMerkleTree::override_range", |b| {
|
||||
let mut offset = 0;
|
||||
b.iter(|| {
|
||||
tree.override_range(0, LEAVES.into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("OptimalMerkleTree::compute_root", |b| {
|
||||
b.iter(|| {
|
||||
tree.compute_root().unwrap();
|
||||
let range = offset..offset + NOF_LEAVES;
|
||||
tree.override_range(
|
||||
offset,
|
||||
LEAVES[range.clone()].iter().cloned(),
|
||||
INDICES[range.clone()].iter().cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
offset = (offset + NOF_LEAVES) % (1 << 20);
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("OptimalMerkleTree::get", |b| {
|
||||
let mut index = 0;
|
||||
b.iter(|| {
|
||||
tree.get(0).unwrap();
|
||||
tree.get(index % NOF_LEAVES).unwrap();
|
||||
index = (index + 1) % NOF_LEAVES;
|
||||
})
|
||||
});
|
||||
|
||||
// check intermediate node getter which required additional computation of sub root index
|
||||
c.bench_function("OptimalMerkleTree::get_subtree_root", |b| {
|
||||
let mut level = 1;
|
||||
let mut index = 0;
|
||||
b.iter(|| {
|
||||
tree.get_subtree_root(1, 0).unwrap();
|
||||
tree.get_subtree_root(level % 20, index % (1 << (20 - (level % 20))))
|
||||
.unwrap();
|
||||
index = (index + 1) % (1 << (20 - (level % 20)));
|
||||
level = 1 + (level % 20);
|
||||
})
|
||||
});
|
||||
|
||||
@@ -108,43 +130,61 @@ pub fn optimal_merkle_tree_benchmark(c: &mut Criterion) {
|
||||
|
||||
pub fn full_merkle_tree_benchmark(c: &mut Criterion) {
|
||||
let mut tree =
|
||||
FullMerkleTree::<Keccak256>::new(2, TestFr([0; 32]), FullMerkleConfig::default()).unwrap();
|
||||
FullMerkleTree::<Keccak256>::new(20, TestFr([0; 32]), FullMerkleConfig::default()).unwrap();
|
||||
|
||||
for i in 0..NOF_LEAVES {
|
||||
tree.set(i, LEAVES[i % LEAVES.len()]).unwrap();
|
||||
}
|
||||
|
||||
c.bench_function("FullMerkleTree::set", |b| {
|
||||
let mut index = NOF_LEAVES;
|
||||
b.iter(|| {
|
||||
tree.set(0, LEAVES[0]).unwrap();
|
||||
tree.set(index % (1 << 20), LEAVES[index % LEAVES.len()])
|
||||
.unwrap();
|
||||
index = (index + 1) % (1 << 20);
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("FullMerkleTree::delete", |b| {
|
||||
let mut index = 0;
|
||||
b.iter(|| {
|
||||
tree.delete(0).unwrap();
|
||||
tree.delete(index % NOF_LEAVES).unwrap();
|
||||
tree.set(index % NOF_LEAVES, LEAVES[index % LEAVES.len()])
|
||||
.unwrap();
|
||||
index = (index + 1) % NOF_LEAVES;
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("FullMerkleTree::override_range", |b| {
|
||||
let mut offset = 0;
|
||||
b.iter(|| {
|
||||
tree.override_range(0, LEAVES.into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("FullMerkleTree::compute_root", |b| {
|
||||
b.iter(|| {
|
||||
tree.compute_root().unwrap();
|
||||
let range = offset..offset + NOF_LEAVES;
|
||||
tree.override_range(
|
||||
offset,
|
||||
LEAVES[range.clone()].iter().cloned(),
|
||||
INDICES[range.clone()].iter().cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
offset = (offset + NOF_LEAVES) % (1 << 20);
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("FullMerkleTree::get", |b| {
|
||||
let mut index = 0;
|
||||
b.iter(|| {
|
||||
tree.get(0).unwrap();
|
||||
tree.get(index % NOF_LEAVES).unwrap();
|
||||
index = (index + 1) % NOF_LEAVES;
|
||||
})
|
||||
});
|
||||
|
||||
// check intermediate node getter which required additional computation of sub root index
|
||||
c.bench_function("FullMerkleTree::get_subtree_root", |b| {
|
||||
let mut level = 1;
|
||||
let mut index = 0;
|
||||
b.iter(|| {
|
||||
tree.get_subtree_root(1, 0).unwrap();
|
||||
tree.get_subtree_root(level % 20, index % (1 << (20 - (level % 20))))
|
||||
.unwrap();
|
||||
index = (index + 1) % (1 << (20 - (level % 20)));
|
||||
level = 1 + (level % 20);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
use crate::merkle_tree::{FrOf, Hasher, ZerokitMerkleProof, ZerokitMerkleTree};
|
||||
use color_eyre::{Report, Result};
|
||||
use std::{
|
||||
cmp::max,
|
||||
fmt::Debug,
|
||||
iter::{once, repeat_n, successors},
|
||||
iter::{once, repeat_n},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use color_eyre::{Report, Result};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use crate::merkle_tree::{FrOf, Hasher, ZerokitMerkleProof, ZerokitMerkleTree, MIN_PARALLEL_NODES};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
///// Full Merkle Tree Implementation
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/// Merkle tree with all leaf and intermediate hashes stored
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct FullMerkleTree<H: Hasher> {
|
||||
pub struct FullMerkleTree<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
/// The depth of the tree, i.e. the number of levels from leaf to root
|
||||
depth: usize,
|
||||
|
||||
/// The nodes cached from the empty part of the tree (where leaves are set to default).
|
||||
/// Since the rightmost part of the tree is usually changed much later than its creation,
|
||||
/// we can prove accumulation of elements in the leftmost part, with no need to initialize the full tree
|
||||
/// and by caching few intermediate nodes to the root computed from default leaves
|
||||
cached_nodes: Vec<H::Fr>,
|
||||
|
||||
/// The tree nodes
|
||||
nodes: Vec<H::Fr>,
|
||||
|
||||
@@ -30,11 +30,11 @@ pub struct FullMerkleTree<H: Hasher> {
|
||||
/// Set to 0 if the leaf is empty and set to 1 in otherwise.
|
||||
cached_leaves_indices: Vec<u8>,
|
||||
|
||||
// The next available (i.e., never used) tree index. Equivalently, the number of leaves added to the tree
|
||||
// (deletions leave next_index unchanged)
|
||||
/// The next available (i.e., never used) tree index. Equivalently, the number of leaves added to the tree
|
||||
/// (deletions leave next_index unchanged)
|
||||
next_index: usize,
|
||||
|
||||
// metadata that an application may use to store additional information
|
||||
/// metadata that an application may use to store additional information
|
||||
metadata: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -78,30 +78,29 @@ where
|
||||
|
||||
/// Creates a new `MerkleTree`
|
||||
/// depth - the height of the tree made only of hash nodes. 2^depth is the maximum number of leaves hash nodes
|
||||
fn new(depth: usize, initial_leaf: FrOf<Self::Hasher>, _config: Self::Config) -> Result<Self> {
|
||||
fn new(depth: usize, default_leaf: FrOf<Self::Hasher>, _config: Self::Config) -> Result<Self> {
|
||||
// Compute cache node values, leaf to root
|
||||
let cached_nodes = successors(Some(initial_leaf), |prev| Some(H::hash(&[*prev, *prev])))
|
||||
.take(depth + 1)
|
||||
.collect::<Vec<_>>();
|
||||
let mut cached_nodes: Vec<H::Fr> = Vec::with_capacity(depth + 1);
|
||||
cached_nodes.push(default_leaf);
|
||||
for i in 0..depth {
|
||||
cached_nodes.push(H::hash(&[cached_nodes[i]; 2]));
|
||||
}
|
||||
cached_nodes.reverse();
|
||||
|
||||
// Compute node values
|
||||
let nodes = cached_nodes
|
||||
.iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
.flat_map(|(levels, hash)| repeat_n(hash, 1 << levels))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
debug_assert!(nodes.len() == (1 << (depth + 1)) - 1);
|
||||
|
||||
let next_index = 0;
|
||||
|
||||
Ok(Self {
|
||||
depth,
|
||||
cached_nodes,
|
||||
nodes,
|
||||
cached_leaves_indices: vec![0; 1 << depth],
|
||||
next_index,
|
||||
next_index: 0,
|
||||
metadata: Vec::new(),
|
||||
})
|
||||
}
|
||||
@@ -110,34 +109,34 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Returns the depth of the tree
|
||||
/// Returns the depth of the tree
|
||||
fn depth(&self) -> usize {
|
||||
self.depth
|
||||
}
|
||||
|
||||
// Returns the capacity of the tree, i.e. the maximum number of accumulatable leaves
|
||||
/// Returns the capacity of the tree, i.e. the maximum number of accumulatable leaves
|
||||
fn capacity(&self) -> usize {
|
||||
1 << self.depth
|
||||
}
|
||||
|
||||
// Returns the total number of leaves set
|
||||
/// Returns the total number of leaves set
|
||||
fn leaves_set(&self) -> usize {
|
||||
self.next_index
|
||||
}
|
||||
|
||||
// Returns the root of the tree
|
||||
/// Returns the root of the tree
|
||||
fn root(&self) -> FrOf<Self::Hasher> {
|
||||
self.nodes[0]
|
||||
}
|
||||
|
||||
// Sets a leaf at the specified tree index
|
||||
/// Sets a leaf at the specified tree index
|
||||
fn set(&mut self, leaf: usize, hash: FrOf<Self::Hasher>) -> Result<()> {
|
||||
self.set_range(leaf, once(hash))?;
|
||||
self.next_index = max(self.next_index, leaf + 1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Get a leaf from the specified tree index
|
||||
/// Get a leaf from the specified tree index
|
||||
fn get(&self, leaf: usize) -> Result<FrOf<Self::Hasher>> {
|
||||
if leaf >= self.capacity() {
|
||||
return Err(Report::msg("leaf index out of bounds"));
|
||||
@@ -145,6 +144,7 @@ where
|
||||
Ok(self.nodes[self.capacity() + leaf - 1])
|
||||
}
|
||||
|
||||
/// Returns the root of the subtree at level n and index
|
||||
fn get_subtree_root(&self, n: usize, index: usize) -> Result<H::Fr> {
|
||||
if n > self.depth() {
|
||||
return Err(Report::msg("level exceeds depth size"));
|
||||
@@ -160,7 +160,7 @@ where
|
||||
let mut idx = self.capacity() + index - 1;
|
||||
let mut nd = self.depth;
|
||||
loop {
|
||||
let parent = self.parent(idx).unwrap();
|
||||
let parent = self.parent(idx).expect("parent should exist");
|
||||
nd -= 1;
|
||||
if nd == n {
|
||||
return Ok(self.nodes[parent]);
|
||||
@@ -171,6 +171,8 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the indices of the leaves that are empty
|
||||
fn get_empty_leaves_indices(&self) -> Vec<usize> {
|
||||
self.cached_leaves_indices
|
||||
.iter()
|
||||
@@ -181,40 +183,40 @@ where
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Sets tree nodes, starting from start index
|
||||
// Function proper of FullMerkleTree implementation
|
||||
fn set_range<I: IntoIterator<Item = FrOf<Self::Hasher>>>(
|
||||
/// Sets multiple leaves from the specified tree index
|
||||
fn set_range<I: ExactSizeIterator<Item = FrOf<Self::Hasher>>>(
|
||||
&mut self,
|
||||
start: usize,
|
||||
hashes: I,
|
||||
leaves: I,
|
||||
) -> Result<()> {
|
||||
let index = self.capacity() + start - 1;
|
||||
let mut count = 0;
|
||||
// first count number of hashes, and check that they fit in the tree
|
||||
// first count number of leaves, and check that they fit in the tree
|
||||
// then insert into the tree
|
||||
let hashes = hashes.into_iter().collect::<Vec<_>>();
|
||||
if hashes.len() + start > self.capacity() {
|
||||
return Err(Report::msg("provided hashes do not fit in the tree"));
|
||||
let leaves = leaves.into_iter().collect::<Vec<_>>();
|
||||
if leaves.len() + start > self.capacity() {
|
||||
return Err(Report::msg("provided leaves do not fit in the tree"));
|
||||
}
|
||||
hashes.into_iter().for_each(|hash| {
|
||||
leaves.into_iter().for_each(|hash| {
|
||||
self.nodes[index + count] = hash;
|
||||
self.cached_leaves_indices[start + count] = 1;
|
||||
count += 1;
|
||||
});
|
||||
if count != 0 {
|
||||
self.update_nodes(index, index + (count - 1))?;
|
||||
self.update_hashes(index, index + (count - 1))?;
|
||||
self.next_index = max(self.next_index, start + count);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Overrides a range of leaves while resetting specified indices to default and preserving unaffected values.
|
||||
fn override_range<I, J>(&mut self, start: usize, leaves: I, indices: J) -> Result<()>
|
||||
where
|
||||
I: IntoIterator<Item = FrOf<Self::Hasher>>,
|
||||
J: IntoIterator<Item = usize>,
|
||||
I: ExactSizeIterator<Item = FrOf<Self::Hasher>>,
|
||||
J: ExactSizeIterator<Item = usize>,
|
||||
{
|
||||
let indices = indices.into_iter().collect::<Vec<_>>();
|
||||
let min_index = *indices.first().unwrap();
|
||||
let min_index = *indices.first().expect("indices should not be empty");
|
||||
let leaves_vec = leaves.into_iter().collect::<Vec<_>>();
|
||||
|
||||
let max_index = start + leaves_vec.len();
|
||||
@@ -240,13 +242,13 @@ where
|
||||
.map_err(|e| Report::msg(e.to_string()))
|
||||
}
|
||||
|
||||
// Sets a leaf at the next available index
|
||||
/// Sets a leaf at the next available index
|
||||
fn update_next(&mut self, leaf: FrOf<Self::Hasher>) -> Result<()> {
|
||||
self.set(self.next_index, leaf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Deletes a leaf at a certain index by setting it to its default value (next_index is not updated)
|
||||
/// Deletes a leaf at a certain index by setting it to its default value (next_index is not updated)
|
||||
fn delete(&mut self, index: usize) -> Result<()> {
|
||||
// We reset the leaf only if we previously set a leaf at that index
|
||||
if index < self.next_index {
|
||||
@@ -280,10 +282,6 @@ where
|
||||
Ok(proof.compute_root_from(hash) == self.root())
|
||||
}
|
||||
|
||||
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
|
||||
Ok(self.root())
|
||||
}
|
||||
|
||||
fn set_metadata(&mut self, metadata: &[u8]) -> Result<()> {
|
||||
self.metadata = metadata.to_vec();
|
||||
Ok(())
|
||||
@@ -294,12 +292,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Utilities for updating the tree nodes
|
||||
impl<H: Hasher> FullMerkleTree<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
// Utilities for updating the tree nodes
|
||||
|
||||
/// For a given node index, return the parent node index
|
||||
/// Returns None if there is no parent (root node)
|
||||
fn parent(&self, index: usize) -> Option<usize> {
|
||||
@@ -315,23 +312,58 @@ where
|
||||
(index << 1) + 1
|
||||
}
|
||||
|
||||
/// Returns the depth level of a node based on its index in the flattened tree.
|
||||
fn levels(&self, index: usize) -> usize {
|
||||
// `n.next_power_of_two()` will return `n` iff `n` is a power of two.
|
||||
// The extra offset corrects this.
|
||||
(index + 2).next_power_of_two().trailing_zeros() as usize - 1
|
||||
}
|
||||
|
||||
fn update_nodes(&mut self, start: usize, end: usize) -> Result<()> {
|
||||
if self.levels(start) != self.levels(end) {
|
||||
return Err(Report::msg("self.levels(start) != self.levels(end)"));
|
||||
/// Updates parent hashes after modifying a range of nodes at the same level.
|
||||
///
|
||||
/// - `start_index`: The first index at the current level that was updated.
|
||||
/// - `end_index`: The last index (inclusive) at the same level that was updated.
|
||||
fn update_hashes(&mut self, start_index: usize, end_index: usize) -> Result<()> {
|
||||
// Ensure the range is within the same tree level
|
||||
if self.levels(start_index) != self.levels(end_index) {
|
||||
return Err(Report::msg(
|
||||
"start_index and end_index must be on the same level",
|
||||
));
|
||||
}
|
||||
if let (Some(start), Some(end)) = (self.parent(start), self.parent(end)) {
|
||||
for parent in start..=end {
|
||||
let child = self.first_child(parent);
|
||||
self.nodes[parent] = H::hash(&[self.nodes[child], self.nodes[child + 1]]);
|
||||
|
||||
// Compute parent indices for the range
|
||||
if let (Some(start_parent), Some(end_parent)) =
|
||||
(self.parent(start_index), self.parent(end_index))
|
||||
{
|
||||
// Use parallel processing when the number of pairs exceeds the threshold
|
||||
if end_parent - start_parent + 1 >= MIN_PARALLEL_NODES {
|
||||
let updates: Vec<(usize, H::Fr)> = (start_parent..=end_parent)
|
||||
.into_par_iter()
|
||||
.map(|parent| {
|
||||
let left_child = self.first_child(parent);
|
||||
let right_child = left_child + 1;
|
||||
let hash = H::hash(&[self.nodes[left_child], self.nodes[right_child]]);
|
||||
(parent, hash)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (parent, hash) in updates {
|
||||
self.nodes[parent] = hash;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, fallback to sequential update for small ranges
|
||||
for parent in start_parent..=end_parent {
|
||||
let left_child = self.first_child(parent);
|
||||
let right_child = left_child + 1;
|
||||
self.nodes[parent] =
|
||||
H::hash(&[self.nodes[left_child], self.nodes[right_child]]);
|
||||
}
|
||||
}
|
||||
self.update_nodes(start, end)?;
|
||||
|
||||
// Recurse to update upper levels
|
||||
self.update_hashes(start_parent, end_parent)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,20 +8,26 @@
|
||||
// and https://github.com/worldcoin/semaphore-rs/blob/d462a4372f1fd9c27610f2acfe4841fab1d396aa/src/merkle_tree.rs
|
||||
|
||||
//!
|
||||
//! # To do
|
||||
//! # TODO
|
||||
//!
|
||||
//! * Disk based storage backend (using mmaped files should be easy)
|
||||
//! * Implement serialization for tree and Merkle proof
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use color_eyre::Result;
|
||||
|
||||
/// Enables parallel hashing when there are at least 8 nodes (4 pairs to hash), justifying the overhead.
|
||||
pub const MIN_PARALLEL_NODES: usize = 8;
|
||||
|
||||
/// In the Hasher trait we define the node type, the default leaf
|
||||
/// and the hash function used to initialize a Merkle Tree implementation
|
||||
pub trait Hasher {
|
||||
/// Type of the leaf and tree node
|
||||
type Fr: Clone + Copy + Eq + Default + std::fmt::Debug + std::fmt::Display + FromStr;
|
||||
type Fr: Clone + Copy + Eq + Default + Debug + Display + FromStr + Send + Sync;
|
||||
|
||||
/// Returns the default tree leaf
|
||||
fn default_leaf() -> Self::Fr;
|
||||
@@ -49,7 +55,6 @@ pub trait ZerokitMerkleTree {
|
||||
fn capacity(&self) -> usize;
|
||||
fn leaves_set(&self) -> usize;
|
||||
fn root(&self) -> FrOf<Self::Hasher>;
|
||||
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>>;
|
||||
fn get_subtree_root(&self, n: usize, index: usize) -> Result<FrOf<Self::Hasher>>;
|
||||
fn set(&mut self, index: usize, leaf: FrOf<Self::Hasher>) -> Result<()>;
|
||||
fn set_range<I>(&mut self, start: usize, leaves: I) -> Result<()>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::merkle_tree::{Hasher, ZerokitMerkleProof, ZerokitMerkleTree};
|
||||
use crate::FrOf;
|
||||
use std::{cmp::max, collections::HashMap, fmt::Debug, str::FromStr};
|
||||
|
||||
use color_eyre::{Report, Result};
|
||||
use std::cmp::min;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::{cmp::max, fmt::Debug};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use crate::merkle_tree::{FrOf, Hasher, ZerokitMerkleProof, ZerokitMerkleTree, MIN_PARALLEL_NODES};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
///// Optimal Merkle Tree Implementation
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -31,11 +31,11 @@ where
|
||||
/// Set to 0 if the leaf is empty and set to 1 in otherwise.
|
||||
cached_leaves_indices: Vec<u8>,
|
||||
|
||||
// The next available (i.e., never used) tree index. Equivalently, the number of leaves added to the tree
|
||||
// (deletions leave next_index unchanged)
|
||||
/// The next available (i.e., never used) tree index. Equivalently, the number of leaves added to the tree
|
||||
/// (deletions leave next_index unchanged)
|
||||
next_index: usize,
|
||||
|
||||
// metadata that an application may use to store additional information
|
||||
/// metadata that an application may use to store additional information
|
||||
metadata: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -55,10 +55,7 @@ impl FromStr for OptimalMerkleConfig {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
///// Implementations
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/// Implementations
|
||||
impl<H: Hasher> ZerokitMerkleTree for OptimalMerkleTree<H>
|
||||
where
|
||||
H: Hasher,
|
||||
@@ -74,15 +71,17 @@ where
|
||||
/// Creates a new `MerkleTree`
|
||||
/// depth - the height of the tree made only of hash nodes. 2^depth is the maximum number of leaves hash nodes
|
||||
fn new(depth: usize, default_leaf: H::Fr, _config: Self::Config) -> Result<Self> {
|
||||
// Compute cache node values, leaf to root
|
||||
let mut cached_nodes: Vec<H::Fr> = Vec::with_capacity(depth + 1);
|
||||
cached_nodes.push(default_leaf);
|
||||
for i in 0..depth {
|
||||
cached_nodes.push(H::hash(&[cached_nodes[i]; 2]));
|
||||
}
|
||||
cached_nodes.reverse();
|
||||
|
||||
Ok(OptimalMerkleTree {
|
||||
cached_nodes,
|
||||
depth,
|
||||
cached_nodes,
|
||||
nodes: HashMap::with_capacity(1 << depth),
|
||||
cached_leaves_indices: vec![0; 1 << depth],
|
||||
next_index: 0,
|
||||
@@ -94,26 +93,47 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Returns the depth of the tree
|
||||
/// Returns the depth of the tree
|
||||
fn depth(&self) -> usize {
|
||||
self.depth
|
||||
}
|
||||
|
||||
// Returns the capacity of the tree, i.e. the maximum number of accumulatable leaves
|
||||
/// Returns the capacity of the tree, i.e. the maximum number of accumulatable leaves
|
||||
fn capacity(&self) -> usize {
|
||||
1 << self.depth
|
||||
}
|
||||
|
||||
// Returns the total number of leaves set
|
||||
/// Returns the total number of leaves set
|
||||
fn leaves_set(&self) -> usize {
|
||||
self.next_index
|
||||
}
|
||||
|
||||
// Returns the root of the tree
|
||||
/// Returns the root of the tree
|
||||
fn root(&self) -> H::Fr {
|
||||
self.get_node(0, 0)
|
||||
}
|
||||
|
||||
/// Sets a leaf at the specified tree index
|
||||
fn set(&mut self, index: usize, leaf: H::Fr) -> Result<()> {
|
||||
if index >= self.capacity() {
|
||||
return Err(Report::msg("index exceeds set size"));
|
||||
}
|
||||
self.nodes.insert((self.depth, index), leaf);
|
||||
self.update_hashes(index, 1)?;
|
||||
self.next_index = max(self.next_index, index + 1);
|
||||
self.cached_leaves_indices[index] = 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a leaf from the specified tree index
|
||||
fn get(&self, index: usize) -> Result<H::Fr> {
|
||||
if index >= self.capacity() {
|
||||
return Err(Report::msg("index exceeds set size"));
|
||||
}
|
||||
Ok(self.get_node(self.depth, index))
|
||||
}
|
||||
|
||||
/// Returns the root of the subtree at level n and index
|
||||
fn get_subtree_root(&self, n: usize, index: usize) -> Result<H::Fr> {
|
||||
if n > self.depth() {
|
||||
return Err(Report::msg("level exceeds depth size"));
|
||||
@@ -130,26 +150,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Sets a leaf at the specified tree index
|
||||
fn set(&mut self, index: usize, leaf: H::Fr) -> Result<()> {
|
||||
if index >= self.capacity() {
|
||||
return Err(Report::msg("index exceeds set size"));
|
||||
}
|
||||
self.nodes.insert((self.depth, index), leaf);
|
||||
self.update_hashes(index, 1)?;
|
||||
self.next_index = max(self.next_index, index + 1);
|
||||
self.cached_leaves_indices[index] = 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Get a leaf from the specified tree index
|
||||
fn get(&self, index: usize) -> Result<H::Fr> {
|
||||
if index >= self.capacity() {
|
||||
return Err(Report::msg("index exceeds set size"));
|
||||
}
|
||||
Ok(self.get_node(self.depth, index))
|
||||
}
|
||||
|
||||
/// Returns the indices of the leaves that are empty
|
||||
fn get_empty_leaves_indices(&self) -> Vec<usize> {
|
||||
self.cached_leaves_indices
|
||||
.iter()
|
||||
@@ -160,7 +161,7 @@ where
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Sets multiple leaves from the specified tree index
|
||||
/// Sets multiple leaves from the specified tree index
|
||||
fn set_range<I: ExactSizeIterator<Item = H::Fr>>(
|
||||
&mut self,
|
||||
start: usize,
|
||||
@@ -180,13 +181,14 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Overrides a range of leaves while resetting specified indices to default and preserving unaffected values.
|
||||
fn override_range<I, J>(&mut self, start: usize, leaves: I, indices: J) -> Result<()>
|
||||
where
|
||||
I: ExactSizeIterator<Item = FrOf<Self::Hasher>>,
|
||||
J: ExactSizeIterator<Item = usize>,
|
||||
{
|
||||
let indices = indices.into_iter().collect::<Vec<_>>();
|
||||
let min_index = *indices.first().unwrap();
|
||||
let min_index = *indices.first().expect("indices should not be empty");
|
||||
let leaves_vec = leaves.into_iter().collect::<Vec<_>>();
|
||||
|
||||
let max_index = start + leaves_vec.len();
|
||||
@@ -195,7 +197,7 @@ where
|
||||
|
||||
for i in min_index..start {
|
||||
if !indices.contains(&i) {
|
||||
let value = self.get_leaf(i);
|
||||
let value = self.get(i)?;
|
||||
set_values[i - min_index] = value;
|
||||
}
|
||||
}
|
||||
@@ -212,13 +214,13 @@ where
|
||||
.map_err(|e| Report::msg(e.to_string()))
|
||||
}
|
||||
|
||||
// Sets a leaf at the next available index
|
||||
/// Sets a leaf at the next available index
|
||||
fn update_next(&mut self, leaf: H::Fr) -> Result<()> {
|
||||
self.set(self.next_index, leaf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Deletes a leaf at a certain index by setting it to its default value (next_index is not updated)
|
||||
/// Deletes a leaf at a certain index by setting it to its default value (next_index is not updated)
|
||||
fn delete(&mut self, index: usize) -> Result<()> {
|
||||
// We reset the leaf only if we previously set a leaf at that index
|
||||
if index < self.next_index {
|
||||
@@ -228,7 +230,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Computes a merkle proof the leaf at the specified index
|
||||
/// Computes a merkle proof the leaf at the specified index
|
||||
fn proof(&self, index: usize) -> Result<Self::Proof> {
|
||||
if index >= self.capacity() {
|
||||
return Err(Report::msg("index exceeds set size"));
|
||||
@@ -238,7 +240,10 @@ where
|
||||
let mut depth = self.depth;
|
||||
loop {
|
||||
i ^= 1;
|
||||
witness.push((self.get_node(depth, i), (1 - (i & 1)).try_into().unwrap()));
|
||||
witness.push((
|
||||
self.get_node(depth, i),
|
||||
(1 - (i & 1)).try_into().expect("0 or 1 expected"),
|
||||
));
|
||||
i >>= 1;
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
@@ -252,7 +257,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies a Merkle proof with respect to the input leaf and the tree root
|
||||
/// Verifies a Merkle proof with respect to the input leaf and the tree root
|
||||
fn verify(&self, leaf: &H::Fr, witness: &Self::Proof) -> Result<bool> {
|
||||
if witness.length() != self.depth {
|
||||
return Err(Report::msg("witness length doesn't match tree depth"));
|
||||
@@ -261,11 +266,6 @@ where
|
||||
Ok(expected_root.eq(&self.root()))
|
||||
}
|
||||
|
||||
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
|
||||
self.recalculate_from(0)?;
|
||||
Ok(self.root())
|
||||
}
|
||||
|
||||
fn set_metadata(&mut self, metadata: &[u8]) -> Result<()> {
|
||||
self.metadata = metadata.to_vec();
|
||||
Ok(())
|
||||
@@ -276,100 +276,75 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Utilities for updating the tree nodes
|
||||
impl<H: Hasher> OptimalMerkleTree<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
// Utilities for updating the tree nodes
|
||||
|
||||
/// Returns the value of a node at a specific (depth, index).
|
||||
/// Falls back to a cached default if the node hasn't been set.
|
||||
fn get_node(&self, depth: usize, index: usize) -> H::Fr {
|
||||
let node = *self
|
||||
*self
|
||||
.nodes
|
||||
.get(&(depth, index))
|
||||
.unwrap_or_else(|| &self.cached_nodes[depth]);
|
||||
node
|
||||
.unwrap_or_else(|| &self.cached_nodes[depth])
|
||||
}
|
||||
|
||||
pub fn get_leaf(&self, index: usize) -> H::Fr {
|
||||
self.get_node(self.depth, index)
|
||||
}
|
||||
|
||||
fn hash_couple(&mut self, depth: usize, index: usize) -> H::Fr {
|
||||
/// Computes the hash of a node’s two children at the given depth.
|
||||
/// If the index is odd, it is rounded down to the nearest even index.
|
||||
fn hash_couple(&self, depth: usize, index: usize) -> H::Fr {
|
||||
let b = index & !1;
|
||||
H::hash(&[self.get_node(depth, b), self.get_node(depth, b + 1)])
|
||||
}
|
||||
|
||||
fn recalculate_from(&mut self, index: usize) -> Result<()> {
|
||||
let mut i = index;
|
||||
let mut depth = self.depth;
|
||||
loop {
|
||||
let h = self.hash_couple(depth, i);
|
||||
i >>= 1;
|
||||
depth -= 1;
|
||||
self.nodes.insert((depth, i), h);
|
||||
self.cached_leaves_indices[index] = 1;
|
||||
if depth == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if depth != 0 {
|
||||
return Err(Report::msg("did not reach the depth"));
|
||||
}
|
||||
if i != 0 {
|
||||
return Err(Report::msg("did not go through all indexes"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update hashes after some leaves have been set or updated
|
||||
/// index - first leaf index (which has been set or updated)
|
||||
/// length - number of elements set or updated
|
||||
fn update_hashes(&mut self, index: usize, length: usize) -> Result<()> {
|
||||
// parent depth & index (used to store in the tree)
|
||||
let mut parent_depth = self.depth - 1; // tree depth (or leaves depth) - 1
|
||||
let mut parent_index = index >> 1;
|
||||
let mut parent_index_bak = parent_index;
|
||||
// maximum index at this depth
|
||||
let parent_max_index_0 = (1 << parent_depth) / 2;
|
||||
// Based on given length (number of elements we will update)
|
||||
// we could restrict the parent_max_index
|
||||
let current_index_max = if (index + length) % 2 == 0 {
|
||||
index + length + 2
|
||||
} else {
|
||||
index + length + 1
|
||||
};
|
||||
let mut parent_max_index = min(current_index_max >> 1, parent_max_index_0);
|
||||
|
||||
// current depth & index (used to compute the hash)
|
||||
// current depth initially == tree depth (or leaves depth)
|
||||
/// Updates parent hashes after modifying a range of leaf nodes.
|
||||
///
|
||||
/// - `start`: Starting leaf index that was updated.
|
||||
/// - `length`: Number of consecutive leaves that were updated.
|
||||
fn update_hashes(&mut self, start: usize, length: usize) -> Result<()> {
|
||||
// Start at the leaf level
|
||||
let mut current_depth = self.depth;
|
||||
let mut current_index = if index % 2 == 0 { index } else { index - 1 };
|
||||
let mut current_index_bak = current_index;
|
||||
|
||||
loop {
|
||||
// Hash 2 values at (current depth, current_index) & (current_depth, current_index + 1)
|
||||
let n_hash = self.hash_couple(current_depth, current_index);
|
||||
// Insert this hash at (parent_depth, parent_index)
|
||||
self.nodes.insert((parent_depth, parent_index), n_hash);
|
||||
// Round down to include the left sibling in the pair (if start is odd)
|
||||
let mut current_index = start & !1;
|
||||
|
||||
if parent_depth == 0 {
|
||||
// We just set the root hash of the tree - nothing to do anymore
|
||||
break;
|
||||
}
|
||||
// Incr parent index
|
||||
parent_index += 1;
|
||||
// Incr current index (+2 because we've just hashed current index & current_index + 1)
|
||||
current_index += 2;
|
||||
if parent_index >= parent_max_index {
|
||||
// reset (aka decr depth & reset indexes)
|
||||
parent_depth -= 1;
|
||||
parent_index = parent_index_bak >> 1;
|
||||
parent_index_bak = parent_index;
|
||||
parent_max_index >>= 1;
|
||||
current_depth -= 1;
|
||||
current_index = current_index_bak >> 1;
|
||||
current_index_bak = current_index;
|
||||
// Compute the max index at this level, round up to include the last updated leaf’s right sibling (if start + length is odd)
|
||||
let mut current_index_max = (start + length + 1) & !1;
|
||||
|
||||
// Traverse from the leaf level up to the root
|
||||
while current_depth > 0 {
|
||||
// Compute the parent level (one level above the current)
|
||||
let parent_depth = current_depth - 1;
|
||||
|
||||
// Use parallel processing when the number of pairs exceeds the threshold
|
||||
if current_index_max - current_index >= MIN_PARALLEL_NODES {
|
||||
let updates: Vec<((usize, usize), H::Fr)> = (current_index..current_index_max)
|
||||
.step_by(2)
|
||||
.collect::<Vec<_>>()
|
||||
.into_par_iter()
|
||||
.map(|index| {
|
||||
// Hash two child nodes at positions (current_depth, index) and (current_depth, index + 1)
|
||||
let hash = self.hash_couple(current_depth, index);
|
||||
// Return the computed parent hash and its position at
|
||||
((parent_depth, index >> 1), hash)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (parent, hash) in updates {
|
||||
self.nodes.insert(parent, hash);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, fallback to sequential update for small ranges
|
||||
for index in (current_index..current_index_max).step_by(2) {
|
||||
let hash = self.hash_couple(current_depth, index);
|
||||
self.nodes.insert((parent_depth, index >> 1), hash);
|
||||
}
|
||||
}
|
||||
|
||||
// Move up one level in the tree
|
||||
current_index >>= 1;
|
||||
current_index_max = (current_index_max + 1) >> 1;
|
||||
current_depth -= 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -383,7 +358,7 @@ where
|
||||
type Index = u8;
|
||||
type Hasher = H;
|
||||
|
||||
// Returns the length of a Merkle proof
|
||||
/// Returns the length of a Merkle proof
|
||||
fn length(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ pub mod test {
|
||||
use tiny_keccak::{Hasher as _, Keccak};
|
||||
use zerokit_utils::{
|
||||
FullMerkleConfig, FullMerkleTree, Hasher, OptimalMerkleConfig, OptimalMerkleTree,
|
||||
ZerokitMerkleProof, ZerokitMerkleTree,
|
||||
ZerokitMerkleProof, ZerokitMerkleTree, MIN_PARALLEL_NODES,
|
||||
};
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
struct Keccak256;
|
||||
@@ -42,7 +42,7 @@ pub mod test {
|
||||
type Err = std::string::FromUtf8Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(TestFr(s.as_bytes().try_into().unwrap()))
|
||||
Ok(TestFr(s.as_bytes().try_into().expect("Invalid length")))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ pub mod test {
|
||||
fn from(value: u32) -> Self {
|
||||
let mut bytes: Vec<u8> = vec![0; 28];
|
||||
bytes.extend_from_slice(&value.to_be_bytes());
|
||||
TestFr(bytes.as_slice().try_into().unwrap())
|
||||
TestFr(bytes.as_slice().try_into().expect("Invalid length"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ pub mod test {
|
||||
|
||||
fn default_full_merkle_tree(depth: usize) -> FullMerkleTree<Keccak256> {
|
||||
FullMerkleTree::<Keccak256>::new(depth, TestFr([0; 32]), FullMerkleConfig::default())
|
||||
.unwrap()
|
||||
.expect("Failed to create FullMerkleTree")
|
||||
}
|
||||
|
||||
fn default_optimal_merkle_tree(depth: usize) -> OptimalMerkleTree<Keccak256> {
|
||||
OptimalMerkleTree::<Keccak256>::new(depth, TestFr([0; 32]), OptimalMerkleConfig::default())
|
||||
.unwrap()
|
||||
.expect("Failed to create OptimalMerkleTree")
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -83,21 +83,101 @@ pub mod test {
|
||||
let nof_leaves = 4;
|
||||
let leaves: Vec<TestFr> = (1..=nof_leaves as u32).map(TestFr::from).collect();
|
||||
|
||||
let mut tree = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
assert_eq!(tree.root(), default_tree_root);
|
||||
let mut tree_full = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
assert_eq!(tree_full.root(), default_tree_root);
|
||||
for i in 0..nof_leaves {
|
||||
tree.set(i, leaves[i]).unwrap();
|
||||
assert_eq!(tree.root(), roots[i]);
|
||||
tree_full.set(i, leaves[i]).expect("Failed to set leaf");
|
||||
assert_eq!(tree_full.root(), roots[i]);
|
||||
}
|
||||
|
||||
let mut tree = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
assert_eq!(tree.root(), default_tree_root);
|
||||
let mut tree_opt = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
assert_eq!(tree_opt.root(), default_tree_root);
|
||||
for i in 0..nof_leaves {
|
||||
tree.set(i, leaves[i]).unwrap();
|
||||
assert_eq!(tree.root(), roots[i]);
|
||||
tree_opt.set(i, leaves[i]).expect("Failed to set leaf");
|
||||
assert_eq!(tree_opt.root(), roots[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_range() {
|
||||
let depth = 4;
|
||||
let leaves: Vec<TestFr> = (0..(1 << depth) as u32).map(TestFr::from).collect();
|
||||
|
||||
let mut tree_full = default_full_merkle_tree(depth);
|
||||
let root_before = tree_full.root();
|
||||
tree_full
|
||||
.set_range(0, leaves.iter().cloned())
|
||||
.expect("Failed to set leaves");
|
||||
let root_after = tree_full.root();
|
||||
assert_ne!(root_before, root_after);
|
||||
|
||||
let mut tree_opt = default_optimal_merkle_tree(depth);
|
||||
let root_before = tree_opt.root();
|
||||
tree_opt
|
||||
.set_range(0, leaves.iter().cloned())
|
||||
.expect("Failed to set leaves");
|
||||
let root_after = tree_opt.root();
|
||||
assert_ne!(root_before, root_after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_next() {
|
||||
let mut tree_full = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
let mut tree_opt = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
|
||||
for i in 0..4 {
|
||||
let leaf = TestFr::from(i as u32);
|
||||
tree_full.update_next(leaf).expect("Failed to update leaf");
|
||||
tree_opt.update_next(leaf).expect("Failed to update leaf");
|
||||
assert_eq!(tree_full.get(i).expect("Failed to get leaf"), leaf);
|
||||
assert_eq!(tree_opt.get(i).expect("Failed to get leaf"), leaf);
|
||||
}
|
||||
|
||||
assert_eq!(tree_full.leaves_set(), 4);
|
||||
assert_eq!(tree_opt.leaves_set(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_and_reset() {
|
||||
let index = 1;
|
||||
let original_leaf = TestFr::from(42);
|
||||
let new_leaf = TestFr::from(99);
|
||||
|
||||
let mut tree_full = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
tree_full
|
||||
.set(index, original_leaf)
|
||||
.expect("Failed to set leaf");
|
||||
let root_with_original = tree_full.root();
|
||||
|
||||
tree_full.delete(index).expect("Failed to delete leaf");
|
||||
let root_after_delete = tree_full.root();
|
||||
assert_ne!(root_with_original, root_after_delete);
|
||||
|
||||
tree_full.set(index, new_leaf).expect("Failed to set leaf");
|
||||
let root_after_reset = tree_full.root();
|
||||
|
||||
assert_ne!(root_after_delete, root_after_reset);
|
||||
assert_ne!(root_with_original, root_after_reset);
|
||||
assert_eq!(tree_full.get(index).expect("Failed to get leaf"), new_leaf);
|
||||
|
||||
let mut tree_opt = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
tree_opt
|
||||
.set(index, original_leaf)
|
||||
.expect("Failed to set leaf");
|
||||
let root_with_original = tree_opt.root();
|
||||
|
||||
tree_opt.delete(index).expect("Failed to delete leaf");
|
||||
let root_after_delete = tree_opt.root();
|
||||
assert_ne!(root_with_original, root_after_delete);
|
||||
|
||||
tree_opt.set(index, new_leaf).expect("Failed to set leaf");
|
||||
let root_after_reset = tree_opt.root();
|
||||
|
||||
assert_ne!(root_after_delete, root_after_reset);
|
||||
assert_ne!(root_with_original, root_after_reset);
|
||||
assert_eq!(tree_opt.get(index).expect("Failed to get leaf"), new_leaf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_empty_leaves_indices() {
|
||||
let depth = 4;
|
||||
@@ -123,31 +203,29 @@ pub mod test {
|
||||
assert_eq!(tree_full.get_empty_leaves_indices(), vec_idxs);
|
||||
}
|
||||
|
||||
// Check situation when the number of items to insert is less than the number of items to delete
|
||||
// check situation when the number of items to insert is less than the number of items to delete
|
||||
tree_full
|
||||
.override_range(0, leaves_2.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
|
||||
// check if the indexes for write and delete are the same
|
||||
tree_full
|
||||
.override_range(0, leaves_4.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
assert_eq!(tree_full.get_empty_leaves_indices(), vec![]);
|
||||
|
||||
// check if indexes for deletion are before indexes for overwriting
|
||||
tree_full
|
||||
.override_range(4, leaves_4.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
assert_eq!(tree_full.get_empty_leaves_indices(), vec![0, 1, 2, 3]);
|
||||
|
||||
// check if the indices for write and delete do not overlap completely
|
||||
tree_full
|
||||
.override_range(2, leaves_4.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
assert_eq!(tree_full.get_empty_leaves_indices(), vec![0, 1]);
|
||||
|
||||
//// Optimal Merkle Tree Trest
|
||||
|
||||
let mut tree_opt = default_optimal_merkle_tree(depth);
|
||||
let _ = tree_opt.set_range(0, leaves.clone().into_iter());
|
||||
assert!(tree_opt.get_empty_leaves_indices().is_empty());
|
||||
@@ -164,27 +242,27 @@ pub mod test {
|
||||
assert_eq!(tree_opt.get_empty_leaves_indices(), vec_idxs);
|
||||
}
|
||||
|
||||
// Check situation when the number of items to insert is less than the number of items to delete
|
||||
// check situation when the number of items to insert is less than the number of items to delete
|
||||
tree_opt
|
||||
.override_range(0, leaves_2.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
|
||||
// check if the indexes for write and delete are the same
|
||||
tree_opt
|
||||
.override_range(0, leaves_4.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
assert_eq!(tree_opt.get_empty_leaves_indices(), vec![]);
|
||||
|
||||
// check if indexes for deletion are before indexes for overwriting
|
||||
tree_opt
|
||||
.override_range(4, leaves_4.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
assert_eq!(tree_opt.get_empty_leaves_indices(), vec![0, 1, 2, 3]);
|
||||
|
||||
// check if the indices for write and delete do not overlap completely
|
||||
tree_opt
|
||||
.override_range(2, leaves_4.clone().into_iter(), [0, 1, 2, 3].into_iter())
|
||||
.unwrap();
|
||||
.expect("Failed to override range");
|
||||
assert_eq!(tree_opt.get_empty_leaves_indices(), vec![0, 1]);
|
||||
}
|
||||
|
||||
@@ -194,18 +272,25 @@ pub mod test {
|
||||
let nof_leaves: usize = 4;
|
||||
let leaves: Vec<TestFr> = (0..nof_leaves as u32).map(TestFr::from).collect();
|
||||
|
||||
let mut tree_full = default_optimal_merkle_tree(depth);
|
||||
let mut tree_full = default_full_merkle_tree(depth);
|
||||
let _ = tree_full.set_range(0, leaves.iter().cloned());
|
||||
|
||||
for i in 0..nof_leaves {
|
||||
// check leaves
|
||||
assert_eq!(
|
||||
tree_full.get(i).unwrap(),
|
||||
tree_full.get_subtree_root(depth, i).unwrap()
|
||||
tree_full.get(i).expect("Failed to get leaf"),
|
||||
tree_full
|
||||
.get_subtree_root(depth, i)
|
||||
.expect("Failed to get subtree root")
|
||||
);
|
||||
|
||||
// check root
|
||||
assert_eq!(tree_full.root(), tree_full.get_subtree_root(0, i).unwrap());
|
||||
assert_eq!(
|
||||
tree_full.root(),
|
||||
tree_full
|
||||
.get_subtree_root(0, i)
|
||||
.expect("Failed to get subtree root")
|
||||
);
|
||||
}
|
||||
|
||||
// check intermediate nodes
|
||||
@@ -215,26 +300,39 @@ pub mod test {
|
||||
let idx_r = (i + 1) * (1 << (depth - n));
|
||||
let idx_sr = idx_l;
|
||||
|
||||
let prev_l = tree_full.get_subtree_root(n, idx_l).unwrap();
|
||||
let prev_r = tree_full.get_subtree_root(n, idx_r).unwrap();
|
||||
let subroot = tree_full.get_subtree_root(n - 1, idx_sr).unwrap();
|
||||
let prev_l = tree_full
|
||||
.get_subtree_root(n, idx_l)
|
||||
.expect("Failed to get subtree root");
|
||||
let prev_r = tree_full
|
||||
.get_subtree_root(n, idx_r)
|
||||
.expect("Failed to get subtree root");
|
||||
let subroot = tree_full
|
||||
.get_subtree_root(n - 1, idx_sr)
|
||||
.expect("Failed to get subtree root");
|
||||
|
||||
// check intermediate nodes
|
||||
assert_eq!(Keccak256::hash(&[prev_l, prev_r]), subroot);
|
||||
}
|
||||
}
|
||||
|
||||
let mut tree_opt = default_full_merkle_tree(depth);
|
||||
let mut tree_opt = default_optimal_merkle_tree(depth);
|
||||
let _ = tree_opt.set_range(0, leaves.iter().cloned());
|
||||
|
||||
for i in 0..nof_leaves {
|
||||
// check leaves
|
||||
assert_eq!(
|
||||
tree_opt.get(i).unwrap(),
|
||||
tree_opt.get_subtree_root(depth, i).unwrap()
|
||||
tree_opt.get(i).expect("Failed to get leaf"),
|
||||
tree_opt
|
||||
.get_subtree_root(depth, i)
|
||||
.expect("Failed to get subtree root")
|
||||
);
|
||||
// check root
|
||||
assert_eq!(tree_opt.root(), tree_opt.get_subtree_root(0, i).unwrap());
|
||||
assert_eq!(
|
||||
tree_opt.root(),
|
||||
tree_opt
|
||||
.get_subtree_root(0, i)
|
||||
.expect("Failed to get subtree root")
|
||||
);
|
||||
}
|
||||
|
||||
// check intermediate nodes
|
||||
@@ -244,9 +342,15 @@ pub mod test {
|
||||
let idx_r = (i + 1) * (1 << (depth - n));
|
||||
let idx_sr = idx_l;
|
||||
|
||||
let prev_l = tree_opt.get_subtree_root(n, idx_l).unwrap();
|
||||
let prev_r = tree_opt.get_subtree_root(n, idx_r).unwrap();
|
||||
let subroot = tree_opt.get_subtree_root(n - 1, idx_sr).unwrap();
|
||||
let prev_l = tree_opt
|
||||
.get_subtree_root(n, idx_l)
|
||||
.expect("Failed to get subtree root");
|
||||
let prev_r = tree_opt
|
||||
.get_subtree_root(n, idx_r)
|
||||
.expect("Failed to get subtree root");
|
||||
let subroot = tree_opt
|
||||
.get_subtree_root(n - 1, idx_sr)
|
||||
.expect("Failed to get subtree root");
|
||||
|
||||
// check intermediate nodes
|
||||
assert_eq!(Keccak256::hash(&[prev_l, prev_r]), subroot);
|
||||
@@ -259,61 +363,83 @@ pub mod test {
|
||||
let nof_leaves = 4;
|
||||
let leaves: Vec<TestFr> = (0..nof_leaves as u32).map(TestFr::from).collect();
|
||||
|
||||
// We thest the FullMerkleTree implementation
|
||||
let mut tree = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
// We test the FullMerkleTree implementation
|
||||
let mut tree_full = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
for i in 0..nof_leaves {
|
||||
// We set the leaves
|
||||
tree.set(i, leaves[i]).unwrap();
|
||||
tree_full.set(i, leaves[i]).expect("Failed to set leaf");
|
||||
|
||||
// We compute a merkle proof
|
||||
let proof = tree.proof(i).expect("index should be set");
|
||||
let proof = tree_full.proof(i).expect("Failed to compute proof");
|
||||
|
||||
// We verify if the merkle proof corresponds to the right leaf index
|
||||
assert_eq!(proof.leaf_index(), i);
|
||||
|
||||
// We verify the proof
|
||||
assert!(tree.verify(&leaves[i], &proof).unwrap());
|
||||
assert!(tree_full
|
||||
.verify(&leaves[i], &proof)
|
||||
.expect("Failed to verify proof"));
|
||||
|
||||
// We ensure that the Merkle proof and the leaf generate the same root as the tree
|
||||
assert_eq!(proof.compute_root_from(&leaves[i]), tree.root());
|
||||
assert_eq!(proof.compute_root_from(&leaves[i]), tree_full.root());
|
||||
|
||||
// We check that the proof is not valid for another leaf
|
||||
assert!(!tree.verify(&leaves[(i + 1) % nof_leaves], &proof).unwrap());
|
||||
assert!(!tree_full
|
||||
.verify(&leaves[(i + 1) % nof_leaves], &proof)
|
||||
.expect("Failed to verify proof"));
|
||||
}
|
||||
|
||||
// We test the OptimalMerkleTree implementation
|
||||
let mut tree = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
let mut tree_opt = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
for i in 0..nof_leaves {
|
||||
// We set the leaves
|
||||
tree.set(i, leaves[i]).unwrap();
|
||||
tree_opt.set(i, leaves[i]).expect("Failed to set leaf");
|
||||
|
||||
// We compute a merkle proof
|
||||
let proof = tree.proof(i).expect("index should be set");
|
||||
let proof = tree_opt.proof(i).expect("Failed to compute proof");
|
||||
|
||||
// We verify if the merkle proof corresponds to the right leaf index
|
||||
assert_eq!(proof.leaf_index(), i);
|
||||
|
||||
// We verify the proof
|
||||
assert!(tree.verify(&leaves[i], &proof).unwrap());
|
||||
assert!(tree_opt
|
||||
.verify(&leaves[i], &proof)
|
||||
.expect("Failed to verify proof"));
|
||||
|
||||
// We ensure that the Merkle proof and the leaf generate the same root as the tree
|
||||
assert_eq!(proof.compute_root_from(&leaves[i]), tree.root());
|
||||
assert_eq!(proof.compute_root_from(&leaves[i]), tree_opt.root());
|
||||
|
||||
// We check that the proof is not valid for another leaf
|
||||
assert!(!tree.verify(&leaves[(i + 1) % nof_leaves], &proof).unwrap());
|
||||
assert!(!tree_opt
|
||||
.verify(&leaves[(i + 1) % nof_leaves], &proof)
|
||||
.expect("Failed to verify proof"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proof_fail() {
|
||||
let tree_full = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
let tree_opt = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
|
||||
let invalid_leaf = TestFr::from(12345);
|
||||
|
||||
let proof_full = tree_full.proof(0).expect("Failed to compute proof");
|
||||
let proof_opt = tree_opt.proof(0).expect("Failed to compute proof");
|
||||
|
||||
// Should fail because no leaf was set
|
||||
assert!(!tree_full
|
||||
.verify(&invalid_leaf, &proof_full)
|
||||
.expect("Failed to verify proof"));
|
||||
assert!(!tree_opt
|
||||
.verify(&invalid_leaf, &proof_opt)
|
||||
.expect("Failed to verify proof"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_override_range() {
|
||||
let nof_leaves = 4;
|
||||
let leaves: Vec<TestFr> = (0..nof_leaves as u32).map(TestFr::from).collect();
|
||||
|
||||
let mut tree = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
|
||||
// We set the leaves
|
||||
tree.set_range(0, leaves.iter().cloned()).unwrap();
|
||||
|
||||
let new_leaves = [
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000005"),
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000006"),
|
||||
@@ -322,17 +448,70 @@ pub mod test {
|
||||
|
||||
let to_delete_indices: [usize; 2] = [0, 1];
|
||||
|
||||
// We override the leaves
|
||||
tree.override_range(
|
||||
0, // start from the end of the initial leaves
|
||||
new_leaves.iter().cloned(),
|
||||
to_delete_indices.iter().cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut tree_full = default_full_merkle_tree(DEFAULT_DEPTH);
|
||||
tree_full
|
||||
.set_range(0, leaves.iter().cloned())
|
||||
.expect("Failed to set leaves");
|
||||
|
||||
tree_full
|
||||
.override_range(
|
||||
0,
|
||||
new_leaves.iter().cloned(),
|
||||
to_delete_indices.iter().cloned(),
|
||||
)
|
||||
.expect("Failed to override range");
|
||||
|
||||
// ensure that the leaves are set correctly
|
||||
for (i, &new_leaf) in new_leaves.iter().enumerate() {
|
||||
assert_eq!(tree.get_leaf(i), new_leaf);
|
||||
assert_eq!(tree_full.get(i).expect("Failed to get leaf"), new_leaf);
|
||||
}
|
||||
|
||||
let mut tree_opt = default_optimal_merkle_tree(DEFAULT_DEPTH);
|
||||
tree_opt
|
||||
.set_range(0, leaves.iter().cloned())
|
||||
.expect("Failed to set leaves");
|
||||
|
||||
tree_opt
|
||||
.override_range(
|
||||
0,
|
||||
new_leaves.iter().cloned(),
|
||||
to_delete_indices.iter().cloned(),
|
||||
)
|
||||
.expect("Failed to override range");
|
||||
|
||||
for (i, &new_leaf) in new_leaves.iter().enumerate() {
|
||||
assert_eq!(tree_opt.get(i).expect("Failed to get leaf"), new_leaf);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_override_range_parallel_triggered() {
|
||||
let depth = 13;
|
||||
let nof_leaves = 8192;
|
||||
|
||||
// number of leaves larger than MIN_PARALLEL_NODES to trigger parallel hashing
|
||||
assert!(MIN_PARALLEL_NODES < nof_leaves);
|
||||
|
||||
let leaves: Vec<TestFr> = (0..nof_leaves as u32).map(TestFr::from).collect();
|
||||
let indices: Vec<usize> = (0..nof_leaves).collect();
|
||||
|
||||
let mut tree_full = default_full_merkle_tree(depth);
|
||||
|
||||
tree_full
|
||||
.override_range(0, leaves.iter().cloned(), indices.iter().cloned())
|
||||
.expect("Failed to override range");
|
||||
|
||||
for (i, &leaf) in leaves.iter().enumerate() {
|
||||
assert_eq!(tree_full.get(i).expect("Failed to get leaf"), leaf);
|
||||
}
|
||||
|
||||
let mut tree_opt = default_optimal_merkle_tree(depth);
|
||||
|
||||
tree_opt
|
||||
.override_range(0, leaves.iter().cloned(), indices.iter().cloned())
|
||||
.expect("Failed to override range");
|
||||
|
||||
for (i, &leaf) in leaves.iter().enumerate() {
|
||||
assert_eq!(tree_opt.get(i).expect("Failed to get leaf"), leaf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user