mirror of
https://github.com/arnaucube/miden-crypto.git
synced 2026-01-12 00:51:29 +01:00
Compare commits
1 Commits
al-update-
...
v0.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d74e746a7f |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,13 +1,3 @@
|
|||||||
## 0.13.0 (TBD)
|
|
||||||
|
|
||||||
- Fixed a bug in the implementation of `draw_integers` for `RpoRandomCoin` (#343).
|
|
||||||
- [BREAKING] Refactor error messages and use `thiserror` to derive errors (#344).
|
|
||||||
- [BREAKING] Updated Winterfell dependency to v0.11 (#346).
|
|
||||||
|
|
||||||
## 0.12.0 (2024-10-30)
|
|
||||||
|
|
||||||
- [BREAKING] Updated Winterfell dependency to v0.10 (#338).
|
|
||||||
|
|
||||||
## 0.11.0 (2024-10-17)
|
## 0.11.0 (2024-10-17)
|
||||||
|
|
||||||
- [BREAKING]: renamed `Mmr::open()` into `Mmr::open_at()` and `Mmr::peaks()` into `Mmr::peaks_at()` (#234).
|
- [BREAKING]: renamed `Mmr::open()` into `Mmr::open_at()` and `Mmr::peaks()` into `Mmr::peaks_at()` (#234).
|
||||||
|
|||||||
150
Cargo.lock
generated
150
Cargo.lock
generated
@@ -19,9 +19,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.18"
|
version = "0.6.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
@@ -34,36 +34,36 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle"
|
name = "anstyle"
|
||||||
version = "1.0.10"
|
version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
version = "0.2.6"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-query"
|
name = "anstyle-query"
|
||||||
version = "1.1.2"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "3.0.6"
|
version = "3.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -78,12 +78,6 @@ version = "0.7.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "assert_matches"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -153,9 +147,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.1"
|
version = "1.1.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
|
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -197,9 +191,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.21"
|
version = "4.5.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -207,9 +201,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.21"
|
version = "4.5.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -231,15 +225,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.3"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.3"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
@@ -249,9 +243,9 @@ checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.16"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
|
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -361,9 +355,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.2.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
@@ -456,9 +450,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.13"
|
version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2"
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
@@ -495,15 +489,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.164"
|
version = "0.2.161"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
|
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.11"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
@@ -525,9 +519,8 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miden-crypto"
|
name = "miden-crypto"
|
||||||
version = "0.13.0"
|
version = "0.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
|
||||||
"blake3",
|
"blake3",
|
||||||
"cc",
|
"cc",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -544,7 +537,6 @@ dependencies = [
|
|||||||
"seq-macro",
|
"seq-macro",
|
||||||
"serde",
|
"serde",
|
||||||
"sha3",
|
"sha3",
|
||||||
"thiserror",
|
|
||||||
"winter-crypto",
|
"winter-crypto",
|
||||||
"winter-math",
|
"winter-math",
|
||||||
"winter-rand-utils",
|
"winter-rand-utils",
|
||||||
@@ -676,9 +668,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.92"
|
version = "1.0.88"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -779,9 +771,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -791,9 +783,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.4.9"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -808,9 +800,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.41"
|
version = "0.38.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
|
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
@@ -854,18 +846,18 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.215"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.215"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -874,9 +866,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.133"
|
version = "1.0.129"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -908,9 +900,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.89"
|
version = "2.0.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
|
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -919,9 +911,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.14.0"
|
version = "3.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
@@ -930,26 +922,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "2.0.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "2.0.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinytemplate"
|
name = "tinytemplate"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@@ -974,9 +946,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
@@ -1173,9 +1145,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-crypto"
|
name = "winter-crypto"
|
||||||
version = "0.11.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67c57748fd2da77742be601f03eda639ff6046879738fd1faae86e80018263cb"
|
checksum = "00fbb724d2d9fbfd3aa16ea27f5e461d4fe1d74b0c9e0ed1bf79e9e2a955f4d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake3",
|
"blake3",
|
||||||
"sha3",
|
"sha3",
|
||||||
@@ -1185,9 +1157,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-math"
|
name = "winter-math"
|
||||||
version = "0.11.0"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6020c17839fa107ce4a7cc178e407ebbc24adfac1980f4fa2111198e052700ab"
|
checksum = "5b0e685b3b872d82e58a86519294a814b7bc7a4d3cd2c93570a7d80c0c5a1aba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"winter-utils",
|
"winter-utils",
|
||||||
@@ -1195,9 +1167,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-rand-utils"
|
name = "winter-rand-utils"
|
||||||
version = "0.11.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "226e4c455f6eb72f64ac6eeb7642df25e21ff2280a4f6b09db75392ad6b390ef"
|
checksum = "f2b827c901ab0c316d89812858ff451d60855c0a5c7ae734b098c62a28624181"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"winter-utils",
|
"winter-utils",
|
||||||
@@ -1205,9 +1177,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-utils"
|
name = "winter-utils"
|
||||||
version = "0.11.0"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1507ef312ea5569d54c2c7446a18b82143eb2a2e21f5c3ec7cfbe8200c03bd7c"
|
checksum = "961e81e9388877a25db1c034ba38253de2055f569633ae6a665d857a0556391b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
|
|||||||
18
Cargo.toml
18
Cargo.toml
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "miden-crypto"
|
name = "miden-crypto"
|
||||||
version = "0.13.0"
|
version = "0.11.0"
|
||||||
description = "Miden Cryptographic primitives"
|
description = "Miden Cryptographic primitives"
|
||||||
authors = ["miden contributors"]
|
authors = ["miden contributors"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/0xPolygonMiden/crypto"
|
repository = "https://github.com/0xPolygonMiden/crypto"
|
||||||
documentation = "https://docs.rs/miden-crypto/0.13.0"
|
documentation = "https://docs.rs/miden-crypto/0.11.0"
|
||||||
categories = ["cryptography", "no-std"]
|
categories = ["cryptography", "no-std"]
|
||||||
keywords = ["miden", "crypto", "hash", "merkle"]
|
keywords = ["miden", "crypto", "hash", "merkle"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -52,24 +52,22 @@ num = { version = "0.4", default-features = false, features = ["alloc", "libm"]
|
|||||||
num-complex = { version = "0.4", default-features = false }
|
num-complex = { version = "0.4", default-features = false }
|
||||||
rand = { version = "0.8", default-features = false }
|
rand = { version = "0.8", default-features = false }
|
||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
rand-utils = { version = "0.11", package = "winter-rand-utils", optional = true }
|
rand-utils = { version = "0.9", package = "winter-rand-utils", optional = true }
|
||||||
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
|
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
|
||||||
sha3 = { version = "0.10", default-features = false }
|
sha3 = { version = "0.10", default-features = false }
|
||||||
thiserror = { version = "2.0", default-features = false }
|
winter-crypto = { version = "0.9", default-features = false }
|
||||||
winter-crypto = { version = "0.11", default-features = false }
|
winter-math = { version = "0.9", default-features = false }
|
||||||
winter-math = { version = "0.11", default-features = false }
|
winter-utils = { version = "0.9", default-features = false }
|
||||||
winter-utils = { version = "0.11", default-features = false }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = { version = "1.5", default-features = false }
|
|
||||||
criterion = { version = "0.5", features = ["html_reports"] }
|
criterion = { version = "0.5", features = ["html_reports"] }
|
||||||
getrandom = { version = "0.2", features = ["js"] }
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
||||||
proptest = "1.5"
|
proptest = "1.5"
|
||||||
rand_chacha = { version = "0.3", default-features = false }
|
rand_chacha = { version = "0.3", default-features = false }
|
||||||
rand-utils = { version = "0.11", package = "winter-rand-utils" }
|
rand-utils = { version = "0.9", package = "winter-rand-utils" }
|
||||||
seq-macro = { version = "0.3" }
|
seq-macro = { version = "0.3" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.2", optional = true, features = ["parallel"] }
|
cc = { version = "1.1", optional = true, features = ["parallel"] }
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use alloc::{string::String, vec::Vec};
|
use alloc::string::String;
|
||||||
use core::{
|
use core::{
|
||||||
mem::{size_of, transmute, transmute_copy},
|
mem::{size_of, transmute, transmute_copy},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
slice::{self, from_raw_parts},
|
slice::from_raw_parts,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Digest, ElementHasher, Felt, FieldElement, Hasher};
|
use super::{Digest, ElementHasher, Felt, FieldElement, Hasher};
|
||||||
@@ -33,14 +33,6 @@ const DIGEST20_BYTES: usize = 20;
|
|||||||
#[cfg_attr(feature = "serde", serde(into = "String", try_from = "&str"))]
|
#[cfg_attr(feature = "serde", serde(into = "String", try_from = "&str"))]
|
||||||
pub struct Blake3Digest<const N: usize>([u8; N]);
|
pub struct Blake3Digest<const N: usize>([u8; N]);
|
||||||
|
|
||||||
impl<const N: usize> Blake3Digest<N> {
|
|
||||||
pub fn digests_as_bytes(digests: &[Blake3Digest<N>]) -> &[u8] {
|
|
||||||
let p = digests.as_ptr();
|
|
||||||
let len = digests.len() * N;
|
|
||||||
unsafe { slice::from_raw_parts(p as *const u8, len) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> Default for Blake3Digest<N> {
|
impl<const N: usize> Default for Blake3Digest<N> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self([0; N])
|
Self([0; N])
|
||||||
@@ -122,10 +114,6 @@ impl Hasher for Blake3_256 {
|
|||||||
Self::hash(prepare_merge(values))
|
Self::hash(prepare_merge(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_many(values: &[Self::Digest]) -> Self::Digest {
|
|
||||||
Blake3Digest(blake3::hash(Blake3Digest::digests_as_bytes(values)).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
||||||
let mut hasher = blake3::Hasher::new();
|
let mut hasher = blake3::Hasher::new();
|
||||||
hasher.update(&seed.0);
|
hasher.update(&seed.0);
|
||||||
@@ -186,11 +174,6 @@ impl Hasher for Blake3_192 {
|
|||||||
Blake3Digest(*shrink_bytes(&blake3::hash(bytes).into()))
|
Blake3Digest(*shrink_bytes(&blake3::hash(bytes).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_many(values: &[Self::Digest]) -> Self::Digest {
|
|
||||||
let bytes: Vec<u8> = values.iter().flat_map(|v| v.as_bytes()).collect();
|
|
||||||
Blake3Digest(*shrink_bytes(&blake3::hash(&bytes).into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
|
fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
|
||||||
Self::hash(prepare_merge(values))
|
Self::hash(prepare_merge(values))
|
||||||
}
|
}
|
||||||
@@ -259,11 +242,6 @@ impl Hasher for Blake3_160 {
|
|||||||
Self::hash(prepare_merge(values))
|
Self::hash(prepare_merge(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_many(values: &[Self::Digest]) -> Self::Digest {
|
|
||||||
let bytes: Vec<u8> = values.iter().flat_map(|v| v.as_bytes()).collect();
|
|
||||||
Blake3Digest(*shrink_bytes(&blake3::hash(&bytes).into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
||||||
let mut hasher = blake3::Hasher::new();
|
let mut hasher = blake3::Hasher::new();
|
||||||
hasher.update(&seed.0);
|
hasher.update(&seed.0);
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::{cmp::Ordering, fmt::Display, ops::Deref, slice};
|
use core::{cmp::Ordering, fmt::Display, ops::Deref};
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO};
|
use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO};
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -36,19 +34,13 @@ impl RpoDigest {
|
|||||||
<Self as Digest>::as_bytes(self)
|
<Self as Digest>::as_bytes(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn digests_as_elements_iter<'a, I>(digests: I) -> impl Iterator<Item = &'a Felt>
|
pub fn digests_as_elements<'a, I>(digests: I) -> impl Iterator<Item = &'a Felt>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a Self>,
|
I: Iterator<Item = &'a Self>,
|
||||||
{
|
{
|
||||||
digests.flat_map(|d| d.0.iter())
|
digests.flat_map(|d| d.0.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn digests_as_elements(digests: &[Self]) -> &[Felt] {
|
|
||||||
let p = digests.as_ptr();
|
|
||||||
let len = digests.len() * DIGEST_SIZE;
|
|
||||||
unsafe { slice::from_raw_parts(p as *const Felt, len) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns hexadecimal representation of this digest prefixed with `0x`.
|
/// Returns hexadecimal representation of this digest prefixed with `0x`.
|
||||||
pub fn to_hex(&self) -> String {
|
pub fn to_hex(&self) -> String {
|
||||||
bytes_to_hex_string(self.as_bytes())
|
bytes_to_hex_string(self.as_bytes())
|
||||||
@@ -129,12 +121,9 @@ impl Randomizable for RpoDigest {
|
|||||||
// CONVERSIONS: FROM RPO DIGEST
|
// CONVERSIONS: FROM RPO DIGEST
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum RpoDigestError {
|
pub enum RpoDigestError {
|
||||||
#[error("failed to convert digest field element to {0}")]
|
InvalidInteger,
|
||||||
TypeConversion(&'static str),
|
|
||||||
#[error("failed to convert to field element: {0}")]
|
|
||||||
InvalidFieldElement(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&RpoDigest> for [bool; DIGEST_SIZE] {
|
impl TryFrom<&RpoDigest> for [bool; DIGEST_SIZE] {
|
||||||
@@ -158,10 +147,10 @@ impl TryFrom<RpoDigest> for [bool; DIGEST_SIZE] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok([
|
Ok([
|
||||||
to_bool(value.0[0].as_int()).ok_or(RpoDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[0].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
|
||||||
to_bool(value.0[1].as_int()).ok_or(RpoDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[1].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
|
||||||
to_bool(value.0[2].as_int()).ok_or(RpoDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[2].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
|
||||||
to_bool(value.0[3].as_int()).ok_or(RpoDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[3].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,22 +168,10 @@ impl TryFrom<RpoDigest> for [u8; DIGEST_SIZE] {
|
|||||||
|
|
||||||
fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
|
fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
|
||||||
Ok([
|
Ok([
|
||||||
value.0[0]
|
value.0[0].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.as_int()
|
value.0[1].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.try_into()
|
value.0[2].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u8"))?,
|
value.0[3].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
value.0[1]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u8"))?,
|
|
||||||
value.0[2]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u8"))?,
|
|
||||||
value.0[3]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u8"))?,
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,22 +189,10 @@ impl TryFrom<RpoDigest> for [u16; DIGEST_SIZE] {
|
|||||||
|
|
||||||
fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
|
fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
|
||||||
Ok([
|
Ok([
|
||||||
value.0[0]
|
value.0[0].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.as_int()
|
value.0[1].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.try_into()
|
value.0[2].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u16"))?,
|
value.0[3].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
value.0[1]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u16"))?,
|
|
||||||
value.0[2]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u16"))?,
|
|
||||||
value.0[3]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u16"))?,
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,22 +210,10 @@ impl TryFrom<RpoDigest> for [u32; DIGEST_SIZE] {
|
|||||||
|
|
||||||
fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
|
fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
|
||||||
Ok([
|
Ok([
|
||||||
value.0[0]
|
value.0[0].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.as_int()
|
value.0[1].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.try_into()
|
value.0[2].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u32"))?,
|
value.0[3].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
value.0[1]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u32"))?,
|
|
||||||
value.0[2]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u32"))?,
|
|
||||||
value.0[3]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpoDigestError::TypeConversion("u32"))?,
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,10 +337,10 @@ impl TryFrom<[u64; DIGEST_SIZE]> for RpoDigest {
|
|||||||
|
|
||||||
fn try_from(value: [u64; DIGEST_SIZE]) -> Result<Self, RpoDigestError> {
|
fn try_from(value: [u64; DIGEST_SIZE]) -> Result<Self, RpoDigestError> {
|
||||||
Ok(Self([
|
Ok(Self([
|
||||||
value[0].try_into().map_err(RpoDigestError::InvalidFieldElement)?,
|
value[0].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
value[1].try_into().map_err(RpoDigestError::InvalidFieldElement)?,
|
value[1].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
value[2].try_into().map_err(RpoDigestError::InvalidFieldElement)?,
|
value[2].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
value[3].try_into().map_err(RpoDigestError::InvalidFieldElement)?,
|
value[3].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ impl Hasher for Rpo256 {
|
|||||||
// initialize the state by copying the digest elements into the rate portion of the state
|
// initialize the state by copying the digest elements into the rate portion of the state
|
||||||
// (8 total elements), and set the capacity elements to 0.
|
// (8 total elements), and set the capacity elements to 0.
|
||||||
let mut state = [ZERO; STATE_WIDTH];
|
let mut state = [ZERO; STATE_WIDTH];
|
||||||
let it = Self::Digest::digests_as_elements_iter(values.iter());
|
let it = Self::Digest::digests_as_elements(values.iter());
|
||||||
for (i, v) in it.enumerate() {
|
for (i, v) in it.enumerate() {
|
||||||
state[RATE_RANGE.start + i] = *v;
|
state[RATE_RANGE.start + i] = *v;
|
||||||
}
|
}
|
||||||
@@ -164,10 +164,6 @@ impl Hasher for Rpo256 {
|
|||||||
RpoDigest::new(state[DIGEST_RANGE].try_into().unwrap())
|
RpoDigest::new(state[DIGEST_RANGE].try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_many(values: &[Self::Digest]) -> Self::Digest {
|
|
||||||
Self::hash_elements(Self::Digest::digests_as_elements(values))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
||||||
// initialize the state as follows:
|
// initialize the state as follows:
|
||||||
// - seed is copied into the first 4 elements of the rate portion of the state.
|
// - seed is copied into the first 4 elements of the rate portion of the state.
|
||||||
@@ -294,7 +290,7 @@ impl Rpo256 {
|
|||||||
// initialize the state by copying the digest elements into the rate portion of the state
|
// initialize the state by copying the digest elements into the rate portion of the state
|
||||||
// (8 total elements), and set the capacity elements to 0.
|
// (8 total elements), and set the capacity elements to 0.
|
||||||
let mut state = [ZERO; STATE_WIDTH];
|
let mut state = [ZERO; STATE_WIDTH];
|
||||||
let it = RpoDigest::digests_as_elements_iter(values.iter());
|
let it = RpoDigest::digests_as_elements(values.iter());
|
||||||
for (i, v) in it.enumerate() {
|
for (i, v) in it.enumerate() {
|
||||||
state[RATE_RANGE.start + i] = *v;
|
state[RATE_RANGE.start + i] = *v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::{cmp::Ordering, fmt::Display, ops::Deref, slice};
|
use core::{cmp::Ordering, fmt::Display, ops::Deref};
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO};
|
use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO};
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -36,19 +34,13 @@ impl RpxDigest {
|
|||||||
<Self as Digest>::as_bytes(self)
|
<Self as Digest>::as_bytes(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn digests_as_elements_iter<'a, I>(digests: I) -> impl Iterator<Item = &'a Felt>
|
pub fn digests_as_elements<'a, I>(digests: I) -> impl Iterator<Item = &'a Felt>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a Self>,
|
I: Iterator<Item = &'a Self>,
|
||||||
{
|
{
|
||||||
digests.flat_map(|d| d.0.iter())
|
digests.flat_map(|d| d.0.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn digests_as_elements(digests: &[Self]) -> &[Felt] {
|
|
||||||
let p = digests.as_ptr();
|
|
||||||
let len = digests.len() * DIGEST_SIZE;
|
|
||||||
unsafe { slice::from_raw_parts(p as *const Felt, len) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns hexadecimal representation of this digest prefixed with `0x`.
|
/// Returns hexadecimal representation of this digest prefixed with `0x`.
|
||||||
pub fn to_hex(&self) -> String {
|
pub fn to_hex(&self) -> String {
|
||||||
bytes_to_hex_string(self.as_bytes())
|
bytes_to_hex_string(self.as_bytes())
|
||||||
@@ -129,12 +121,9 @@ impl Randomizable for RpxDigest {
|
|||||||
// CONVERSIONS: FROM RPX DIGEST
|
// CONVERSIONS: FROM RPX DIGEST
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum RpxDigestError {
|
pub enum RpxDigestError {
|
||||||
#[error("failed to convert digest field element to {0}")]
|
InvalidInteger,
|
||||||
TypeConversion(&'static str),
|
|
||||||
#[error("failed to convert to field element: {0}")]
|
|
||||||
InvalidFieldElement(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&RpxDigest> for [bool; DIGEST_SIZE] {
|
impl TryFrom<&RpxDigest> for [bool; DIGEST_SIZE] {
|
||||||
@@ -158,10 +147,10 @@ impl TryFrom<RpxDigest> for [bool; DIGEST_SIZE] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok([
|
Ok([
|
||||||
to_bool(value.0[0].as_int()).ok_or(RpxDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[0].as_int()).ok_or(RpxDigestError::InvalidInteger)?,
|
||||||
to_bool(value.0[1].as_int()).ok_or(RpxDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[1].as_int()).ok_or(RpxDigestError::InvalidInteger)?,
|
||||||
to_bool(value.0[2].as_int()).ok_or(RpxDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[2].as_int()).ok_or(RpxDigestError::InvalidInteger)?,
|
||||||
to_bool(value.0[3].as_int()).ok_or(RpxDigestError::TypeConversion("bool"))?,
|
to_bool(value.0[3].as_int()).ok_or(RpxDigestError::InvalidInteger)?,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,22 +168,10 @@ impl TryFrom<RpxDigest> for [u8; DIGEST_SIZE] {
|
|||||||
|
|
||||||
fn try_from(value: RpxDigest) -> Result<Self, Self::Error> {
|
fn try_from(value: RpxDigest) -> Result<Self, Self::Error> {
|
||||||
Ok([
|
Ok([
|
||||||
value.0[0]
|
value.0[0].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.as_int()
|
value.0[1].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.try_into()
|
value.0[2].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u8"))?,
|
value.0[3].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
value.0[1]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u8"))?,
|
|
||||||
value.0[2]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u8"))?,
|
|
||||||
value.0[3]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u8"))?,
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,22 +189,10 @@ impl TryFrom<RpxDigest> for [u16; DIGEST_SIZE] {
|
|||||||
|
|
||||||
fn try_from(value: RpxDigest) -> Result<Self, Self::Error> {
|
fn try_from(value: RpxDigest) -> Result<Self, Self::Error> {
|
||||||
Ok([
|
Ok([
|
||||||
value.0[0]
|
value.0[0].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.as_int()
|
value.0[1].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.try_into()
|
value.0[2].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u16"))?,
|
value.0[3].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
value.0[1]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u16"))?,
|
|
||||||
value.0[2]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u16"))?,
|
|
||||||
value.0[3]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u16"))?,
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,22 +210,10 @@ impl TryFrom<RpxDigest> for [u32; DIGEST_SIZE] {
|
|||||||
|
|
||||||
fn try_from(value: RpxDigest) -> Result<Self, Self::Error> {
|
fn try_from(value: RpxDigest) -> Result<Self, Self::Error> {
|
||||||
Ok([
|
Ok([
|
||||||
value.0[0]
|
value.0[0].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.as_int()
|
value.0[1].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.try_into()
|
value.0[2].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u32"))?,
|
value.0[3].as_int().try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
value.0[1]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u32"))?,
|
|
||||||
value.0[2]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u32"))?,
|
|
||||||
value.0[3]
|
|
||||||
.as_int()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| RpxDigestError::TypeConversion("u32"))?,
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,10 +337,10 @@ impl TryFrom<[u64; DIGEST_SIZE]> for RpxDigest {
|
|||||||
|
|
||||||
fn try_from(value: [u64; DIGEST_SIZE]) -> Result<Self, RpxDigestError> {
|
fn try_from(value: [u64; DIGEST_SIZE]) -> Result<Self, RpxDigestError> {
|
||||||
Ok(Self([
|
Ok(Self([
|
||||||
value[0].try_into().map_err(RpxDigestError::InvalidFieldElement)?,
|
value[0].try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
value[1].try_into().map_err(RpxDigestError::InvalidFieldElement)?,
|
value[1].try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
value[2].try_into().map_err(RpxDigestError::InvalidFieldElement)?,
|
value[2].try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
value[3].try_into().map_err(RpxDigestError::InvalidFieldElement)?,
|
value[3].try_into().map_err(|_| RpxDigestError::InvalidInteger)?,
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ impl Hasher for Rpx256 {
|
|||||||
// initialize the state by copying the digest elements into the rate portion of the state
|
// initialize the state by copying the digest elements into the rate portion of the state
|
||||||
// (8 total elements), and set the capacity elements to 0.
|
// (8 total elements), and set the capacity elements to 0.
|
||||||
let mut state = [ZERO; STATE_WIDTH];
|
let mut state = [ZERO; STATE_WIDTH];
|
||||||
let it = Self::Digest::digests_as_elements_iter(values.iter());
|
let it = Self::Digest::digests_as_elements(values.iter());
|
||||||
for (i, v) in it.enumerate() {
|
for (i, v) in it.enumerate() {
|
||||||
state[RATE_RANGE.start + i] = *v;
|
state[RATE_RANGE.start + i] = *v;
|
||||||
}
|
}
|
||||||
@@ -170,10 +170,6 @@ impl Hasher for Rpx256 {
|
|||||||
RpxDigest::new(state[DIGEST_RANGE].try_into().unwrap())
|
RpxDigest::new(state[DIGEST_RANGE].try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_many(values: &[Self::Digest]) -> Self::Digest {
|
|
||||||
Self::hash_elements(Self::Digest::digests_as_elements(values))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
|
||||||
// initialize the state as follows:
|
// initialize the state as follows:
|
||||||
// - seed is copied into the first 4 elements of the rate portion of the state.
|
// - seed is copied into the first 4 elements of the rate portion of the state.
|
||||||
@@ -297,7 +293,7 @@ impl Rpx256 {
|
|||||||
// initialize the state by copying the digest elements into the rate portion of the state
|
// initialize the state by copying the digest elements into the rate portion of the state
|
||||||
// (8 total elements), and set the capacity elements to 0.
|
// (8 total elements), and set the capacity elements to 0.
|
||||||
let mut state = [ZERO; STATE_WIDTH];
|
let mut state = [ZERO; STATE_WIDTH];
|
||||||
let it = RpxDigest::digests_as_elements_iter(values.iter());
|
let it = RpxDigest::digests_as_elements(values.iter());
|
||||||
for (i, v) in it.enumerate() {
|
for (i, v) in it.enumerate() {
|
||||||
state[RATE_RANGE.start + i] = *v;
|
state[RATE_RANGE.start + i] = *v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,65 @@
|
|||||||
use thiserror::Error;
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
use super::{NodeIndex, RpoDigest};
|
use super::{smt::SmtLeafError, MerklePath, NodeIndex, RpoDigest};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Error, Eq, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum MerkleError {
|
pub enum MerkleError {
|
||||||
#[error("expected merkle root {expected_root} found {actual_root}")]
|
ConflictingRoots(Vec<RpoDigest>),
|
||||||
ConflictingRoots {
|
|
||||||
expected_root: RpoDigest,
|
|
||||||
actual_root: RpoDigest,
|
|
||||||
},
|
|
||||||
#[error("provided merkle tree depth {0} is too small")]
|
|
||||||
DepthTooSmall(u8),
|
DepthTooSmall(u8),
|
||||||
#[error("provided merkle tree depth {0} is too big")]
|
|
||||||
DepthTooBig(u64),
|
DepthTooBig(u64),
|
||||||
#[error("multiple values provided for merkle tree index {0}")]
|
|
||||||
DuplicateValuesForIndex(u64),
|
DuplicateValuesForIndex(u64),
|
||||||
#[error("node index value {value} is not valid for depth {depth}")]
|
DuplicateValuesForKey(RpoDigest),
|
||||||
InvalidNodeIndex { depth: u8, value: u64 },
|
InvalidIndex { depth: u8, value: u64 },
|
||||||
#[error("provided node index depth {provided} does not match expected depth {expected}")]
|
InvalidDepth { expected: u8, provided: u8 },
|
||||||
InvalidNodeIndexDepth { expected: u8, provided: u8 },
|
InvalidSubtreeDepth { subtree_depth: u8, tree_depth: u8 },
|
||||||
#[error("merkle subtree depth {subtree_depth} exceeds merkle tree depth {tree_depth}")]
|
InvalidPath(MerklePath),
|
||||||
SubtreeDepthExceedsDepth { subtree_depth: u8, tree_depth: u8 },
|
InvalidNumEntries(usize),
|
||||||
#[error("number of entries in the merkle tree exceeds the maximum of {0}")]
|
NodeNotInSet(NodeIndex),
|
||||||
TooManyEntries(usize),
|
NodeNotInStore(RpoDigest, NodeIndex),
|
||||||
#[error("node index `{0}` not found in the tree")]
|
|
||||||
NodeIndexNotFoundInTree(NodeIndex),
|
|
||||||
#[error("node {0:?} with index `{1}` not found in the store")]
|
|
||||||
NodeIndexNotFoundInStore(RpoDigest, NodeIndex),
|
|
||||||
#[error("number of provided merkle tree leaves {0} is not a power of two")]
|
|
||||||
NumLeavesNotPowerOfTwo(usize),
|
NumLeavesNotPowerOfTwo(usize),
|
||||||
#[error("root {0:?} is not in the store")]
|
|
||||||
RootNotInStore(RpoDigest),
|
RootNotInStore(RpoDigest),
|
||||||
|
SmtLeaf(SmtLeafError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MerkleError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use MerkleError::*;
|
||||||
|
match self {
|
||||||
|
ConflictingRoots(roots) => write!(f, "the merkle paths roots do not match {roots:?}"),
|
||||||
|
DepthTooSmall(depth) => write!(f, "the provided depth {depth} is too small"),
|
||||||
|
DepthTooBig(depth) => write!(f, "the provided depth {depth} is too big"),
|
||||||
|
DuplicateValuesForIndex(key) => write!(f, "multiple values provided for key {key}"),
|
||||||
|
DuplicateValuesForKey(key) => write!(f, "multiple values provided for key {key}"),
|
||||||
|
InvalidIndex { depth, value } => {
|
||||||
|
write!(f, "the index value {value} is not valid for the depth {depth}")
|
||||||
|
},
|
||||||
|
InvalidDepth { expected, provided } => {
|
||||||
|
write!(f, "the provided depth {provided} is not valid for {expected}")
|
||||||
|
},
|
||||||
|
InvalidSubtreeDepth { subtree_depth, tree_depth } => {
|
||||||
|
write!(f, "tried inserting a subtree of depth {subtree_depth} into a tree of depth {tree_depth}")
|
||||||
|
},
|
||||||
|
InvalidPath(_path) => write!(f, "the provided path is not valid"),
|
||||||
|
InvalidNumEntries(max) => write!(f, "number of entries exceeded the maximum: {max}"),
|
||||||
|
NodeNotInSet(index) => write!(f, "the node with index ({index}) is not in the set"),
|
||||||
|
NodeNotInStore(hash, index) => {
|
||||||
|
write!(f, "the node {hash:?} with index ({index}) is not in the store")
|
||||||
|
},
|
||||||
|
NumLeavesNotPowerOfTwo(leaves) => {
|
||||||
|
write!(f, "the leaves count {leaves} is not a power of 2")
|
||||||
|
},
|
||||||
|
RootNotInStore(root) => write!(f, "the root {:?} is not in the store", root),
|
||||||
|
SmtLeaf(smt_leaf_error) => write!(f, "smt leaf error: {smt_leaf_error}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for MerkleError {}
|
||||||
|
|
||||||
|
impl From<SmtLeafError> for MerkleError {
|
||||||
|
fn from(value: SmtLeafError) -> Self {
|
||||||
|
Self::SmtLeaf(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ impl NodeIndex {
|
|||||||
/// Returns an error if the `value` is greater than or equal to 2^{depth}.
|
/// Returns an error if the `value` is greater than or equal to 2^{depth}.
|
||||||
pub const fn new(depth: u8, value: u64) -> Result<Self, MerkleError> {
|
pub const fn new(depth: u8, value: u64) -> Result<Self, MerkleError> {
|
||||||
if (64 - value.leading_zeros()) > depth as u32 {
|
if (64 - value.leading_zeros()) > depth as u32 {
|
||||||
Err(MerkleError::InvalidNodeIndex { depth, value })
|
Err(MerkleError::InvalidIndex { depth, value })
|
||||||
} else {
|
} else {
|
||||||
Ok(Self { depth, value })
|
Ok(Self { depth, value })
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,6 @@ impl Deserializable for NodeIndex {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use assert_matches::assert_matches;
|
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -191,19 +190,19 @@ mod tests {
|
|||||||
fn test_node_index_value_too_high() {
|
fn test_node_index_value_too_high() {
|
||||||
assert_eq!(NodeIndex::new(0, 0).unwrap(), NodeIndex { depth: 0, value: 0 });
|
assert_eq!(NodeIndex::new(0, 0).unwrap(), NodeIndex { depth: 0, value: 0 });
|
||||||
let err = NodeIndex::new(0, 1).unwrap_err();
|
let err = NodeIndex::new(0, 1).unwrap_err();
|
||||||
assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 0, value: 1 });
|
assert_eq!(err, MerkleError::InvalidIndex { depth: 0, value: 1 });
|
||||||
|
|
||||||
assert_eq!(NodeIndex::new(1, 1).unwrap(), NodeIndex { depth: 1, value: 1 });
|
assert_eq!(NodeIndex::new(1, 1).unwrap(), NodeIndex { depth: 1, value: 1 });
|
||||||
let err = NodeIndex::new(1, 2).unwrap_err();
|
let err = NodeIndex::new(1, 2).unwrap_err();
|
||||||
assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 1, value: 2 });
|
assert_eq!(err, MerkleError::InvalidIndex { depth: 1, value: 2 });
|
||||||
|
|
||||||
assert_eq!(NodeIndex::new(2, 3).unwrap(), NodeIndex { depth: 2, value: 3 });
|
assert_eq!(NodeIndex::new(2, 3).unwrap(), NodeIndex { depth: 2, value: 3 });
|
||||||
let err = NodeIndex::new(2, 4).unwrap_err();
|
let err = NodeIndex::new(2, 4).unwrap_err();
|
||||||
assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 2, value: 4 });
|
assert_eq!(err, MerkleError::InvalidIndex { depth: 2, value: 4 });
|
||||||
|
|
||||||
assert_eq!(NodeIndex::new(3, 7).unwrap(), NodeIndex { depth: 3, value: 7 });
|
assert_eq!(NodeIndex::new(3, 7).unwrap(), NodeIndex { depth: 3, value: 7 });
|
||||||
let err = NodeIndex::new(3, 8).unwrap_err();
|
let err = NodeIndex::new(3, 8).unwrap_err();
|
||||||
assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 3, value: 8 });
|
assert_eq!(err, MerkleError::InvalidIndex { depth: 3, value: 8 });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,27 +1,41 @@
|
|||||||
use alloc::string::String;
|
use core::fmt::{Display, Formatter};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
use thiserror::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use crate::merkle::MerkleError;
|
use crate::merkle::MerkleError;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum MmrError {
|
pub enum MmrError {
|
||||||
#[error("mmr does not contain position {0}")]
|
InvalidPosition(usize),
|
||||||
PositionNotFound(usize),
|
InvalidPeaks,
|
||||||
#[error("mmr peaks are invalid: {0}")]
|
InvalidPeak,
|
||||||
InvalidPeaks(String),
|
PeakOutOfBounds(usize, usize),
|
||||||
#[error(
|
|
||||||
"mmr peak does not match the computed merkle root of the provided authentication path"
|
|
||||||
)]
|
|
||||||
PeakPathMismatch,
|
|
||||||
#[error("requested peak index is {peak_idx} but the number of peaks is {peaks_len}")]
|
|
||||||
PeakOutOfBounds { peak_idx: usize, peaks_len: usize },
|
|
||||||
#[error("invalid mmr update")]
|
|
||||||
InvalidUpdate,
|
InvalidUpdate,
|
||||||
#[error("mmr does not contain a peak with depth {0}")]
|
UnknownPeak,
|
||||||
UnknownPeak(u8),
|
MerkleError(MerkleError),
|
||||||
#[error("invalid merkle path")]
|
|
||||||
InvalidMerklePath(#[source] MerkleError),
|
|
||||||
#[error("merkle root computation failed")]
|
|
||||||
MerkleRootComputationFailed(#[source] MerkleError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for MmrError {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||||
|
match self {
|
||||||
|
MmrError::InvalidPosition(pos) => write!(fmt, "Mmr does not contain position {pos}"),
|
||||||
|
MmrError::InvalidPeaks => write!(fmt, "Invalid peaks count"),
|
||||||
|
MmrError::InvalidPeak => {
|
||||||
|
write!(fmt, "Peak values does not match merkle path computed root")
|
||||||
|
},
|
||||||
|
MmrError::PeakOutOfBounds(peak_idx, peaks_len) => write!(
|
||||||
|
fmt,
|
||||||
|
"Requested peak index is {} but the number of peaks is {}",
|
||||||
|
peak_idx, peaks_len
|
||||||
|
),
|
||||||
|
MmrError::InvalidUpdate => write!(fmt, "Invalid Mmr update"),
|
||||||
|
MmrError::UnknownPeak => {
|
||||||
|
write!(fmt, "Peak not in Mmr")
|
||||||
|
},
|
||||||
|
MmrError::MerkleError(err) => write!(fmt, "{}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl Error for MmrError {}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ impl Mmr {
|
|||||||
pub fn open_at(&self, pos: usize, forest: usize) -> Result<MmrProof, MmrError> {
|
pub fn open_at(&self, pos: usize, forest: usize) -> Result<MmrProof, MmrError> {
|
||||||
// find the target tree responsible for the MMR position
|
// find the target tree responsible for the MMR position
|
||||||
let tree_bit =
|
let tree_bit =
|
||||||
leaf_to_corresponding_tree(pos, forest).ok_or(MmrError::PositionNotFound(pos))?;
|
leaf_to_corresponding_tree(pos, forest).ok_or(MmrError::InvalidPosition(pos))?;
|
||||||
|
|
||||||
// isolate the trees before the target
|
// isolate the trees before the target
|
||||||
let forest_before = forest & high_bitmask(tree_bit + 1);
|
let forest_before = forest & high_bitmask(tree_bit + 1);
|
||||||
@@ -126,7 +126,7 @@ impl Mmr {
|
|||||||
pub fn get(&self, pos: usize) -> Result<RpoDigest, MmrError> {
|
pub fn get(&self, pos: usize) -> Result<RpoDigest, MmrError> {
|
||||||
// find the target tree responsible for the MMR position
|
// find the target tree responsible for the MMR position
|
||||||
let tree_bit =
|
let tree_bit =
|
||||||
leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::PositionNotFound(pos))?;
|
leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::InvalidPosition(pos))?;
|
||||||
|
|
||||||
// isolate the trees before the target
|
// isolate the trees before the target
|
||||||
let forest_before = self.forest & high_bitmask(tree_bit + 1);
|
let forest_before = self.forest & high_bitmask(tree_bit + 1);
|
||||||
@@ -174,10 +174,7 @@ impl Mmr {
|
|||||||
/// Returns an error if the specified `forest` value is not valid for this MMR.
|
/// Returns an error if the specified `forest` value is not valid for this MMR.
|
||||||
pub fn peaks_at(&self, forest: usize) -> Result<MmrPeaks, MmrError> {
|
pub fn peaks_at(&self, forest: usize) -> Result<MmrPeaks, MmrError> {
|
||||||
if forest > self.forest {
|
if forest > self.forest {
|
||||||
return Err(MmrError::InvalidPeaks(format!(
|
return Err(MmrError::InvalidPeaks);
|
||||||
"requested forest {forest} exceeds current forest {}",
|
|
||||||
self.forest
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let peaks: Vec<RpoDigest> = TrueBitPositionIterator::new(forest)
|
let peaks: Vec<RpoDigest> = TrueBitPositionIterator::new(forest)
|
||||||
@@ -202,7 +199,7 @@ impl Mmr {
|
|||||||
/// that have been merged together, followed by the new peaks of the [Mmr].
|
/// that have been merged together, followed by the new peaks of the [Mmr].
|
||||||
pub fn get_delta(&self, from_forest: usize, to_forest: usize) -> Result<MmrDelta, MmrError> {
|
pub fn get_delta(&self, from_forest: usize, to_forest: usize) -> Result<MmrDelta, MmrError> {
|
||||||
if to_forest > self.forest || from_forest > to_forest {
|
if to_forest > self.forest || from_forest > to_forest {
|
||||||
return Err(MmrError::InvalidPeaks(format!("to_forest {to_forest} exceeds the current forest {} or from_forest {from_forest} exceeds to_forest", self.forest)));
|
return Err(MmrError::InvalidPeaks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if from_forest == to_forest {
|
if from_forest == to_forest {
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ impl PartialMmr {
|
|||||||
/// in the underlying MMR.
|
/// in the underlying MMR.
|
||||||
pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
|
pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
|
||||||
let tree_bit =
|
let tree_bit =
|
||||||
leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::PositionNotFound(pos))?;
|
leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::InvalidPosition(pos))?;
|
||||||
let depth = tree_bit as usize;
|
let depth = tree_bit as usize;
|
||||||
|
|
||||||
let mut nodes = Vec::with_capacity(depth);
|
let mut nodes = Vec::with_capacity(depth);
|
||||||
@@ -298,7 +298,7 @@ impl PartialMmr {
|
|||||||
// invalid.
|
// invalid.
|
||||||
let tree = 1 << path.depth();
|
let tree = 1 << path.depth();
|
||||||
if tree & self.forest == 0 {
|
if tree & self.forest == 0 {
|
||||||
return Err(MmrError::UnknownPeak(path.depth()));
|
return Err(MmrError::UnknownPeak);
|
||||||
};
|
};
|
||||||
|
|
||||||
if leaf_pos + 1 == self.forest
|
if leaf_pos + 1 == self.forest
|
||||||
@@ -319,11 +319,9 @@ impl PartialMmr {
|
|||||||
|
|
||||||
// Compute the root of the authentication path, and check it matches the current version of
|
// Compute the root of the authentication path, and check it matches the current version of
|
||||||
// the PartialMmr.
|
// the PartialMmr.
|
||||||
let computed = path
|
let computed = path.compute_root(path_idx as u64, leaf).map_err(MmrError::MerkleError)?;
|
||||||
.compute_root(path_idx as u64, leaf)
|
|
||||||
.map_err(MmrError::MerkleRootComputationFailed)?;
|
|
||||||
if self.peaks[peak_pos] != computed {
|
if self.peaks[peak_pos] != computed {
|
||||||
return Err(MmrError::PeakPathMismatch);
|
return Err(MmrError::InvalidPeak);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
|
let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
|
||||||
@@ -358,10 +356,7 @@ impl PartialMmr {
|
|||||||
/// inserted into the partial MMR.
|
/// inserted into the partial MMR.
|
||||||
pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, RpoDigest)>, MmrError> {
|
pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, RpoDigest)>, MmrError> {
|
||||||
if delta.forest < self.forest {
|
if delta.forest < self.forest {
|
||||||
return Err(MmrError::InvalidPeaks(format!(
|
return Err(MmrError::InvalidPeaks);
|
||||||
"forest of mmr delta {} is less than current forest {}",
|
|
||||||
delta.forest, self.forest
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut inserted_nodes = Vec::new();
|
let mut inserted_nodes = Vec::new();
|
||||||
|
|||||||
@@ -45,11 +45,7 @@ impl MmrPeaks {
|
|||||||
/// Returns an error if the number of leaves and the number of peaks are inconsistent.
|
/// Returns an error if the number of leaves and the number of peaks are inconsistent.
|
||||||
pub fn new(num_leaves: usize, peaks: Vec<RpoDigest>) -> Result<Self, MmrError> {
|
pub fn new(num_leaves: usize, peaks: Vec<RpoDigest>) -> Result<Self, MmrError> {
|
||||||
if num_leaves.count_ones() as usize != peaks.len() {
|
if num_leaves.count_ones() as usize != peaks.len() {
|
||||||
return Err(MmrError::InvalidPeaks(format!(
|
return Err(MmrError::InvalidPeaks);
|
||||||
"number of one bits in leaves is {} which does not equal peak length {}",
|
|
||||||
num_leaves.count_ones(),
|
|
||||||
peaks.len()
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { num_leaves, peaks })
|
Ok(Self { num_leaves, peaks })
|
||||||
@@ -81,7 +77,7 @@ impl MmrPeaks {
|
|||||||
pub fn get_peak(&self, peak_idx: usize) -> Result<&RpoDigest, MmrError> {
|
pub fn get_peak(&self, peak_idx: usize) -> Result<&RpoDigest, MmrError> {
|
||||||
self.peaks
|
self.peaks
|
||||||
.get(peak_idx)
|
.get(peak_idx)
|
||||||
.ok_or(MmrError::PeakOutOfBounds { peak_idx, peaks_len: self.peaks.len() })
|
.ok_or(MmrError::PeakOutOfBounds(peak_idx, self.peaks.len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this [MmrPeaks] into its components: number of leaves and a vector of peaks of
|
/// Converts this [MmrPeaks] into its components: number of leaves and a vector of peaks of
|
||||||
@@ -110,7 +106,7 @@ impl MmrPeaks {
|
|||||||
opening
|
opening
|
||||||
.merkle_path
|
.merkle_path
|
||||||
.verify(opening.relative_pos() as u64, value, root)
|
.verify(opening.relative_pos() as u64, value, root)
|
||||||
.map_err(MmrError::InvalidMerklePath)
|
.map_err(MmrError::MerkleError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flattens and pads the peaks to make hashing inside of the Miden VM easier.
|
/// Flattens and pads the peaks to make hashing inside of the Miden VM easier.
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl PartialMerkleTree {
|
|||||||
// depth of 63 because we consider passing in a vector of size 2^64 infeasible.
|
// depth of 63 because we consider passing in a vector of size 2^64 infeasible.
|
||||||
let max = 2usize.pow(63);
|
let max = 2usize.pow(63);
|
||||||
if layers.len() > max {
|
if layers.len() > max {
|
||||||
return Err(MerkleError::TooManyEntries(max));
|
return Err(MerkleError::InvalidNumEntries(max));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get maximum depth
|
// Get maximum depth
|
||||||
@@ -147,12 +147,11 @@ impl PartialMerkleTree {
|
|||||||
let index = NodeIndex::new(depth, index_value)?;
|
let index = NodeIndex::new(depth, index_value)?;
|
||||||
|
|
||||||
// get hash of the current node
|
// get hash of the current node
|
||||||
let node =
|
let node = nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index))?;
|
||||||
nodes.get(&index).ok_or(MerkleError::NodeIndexNotFoundInTree(index))?;
|
|
||||||
// get hash of the sibling node
|
// get hash of the sibling node
|
||||||
let sibling = nodes
|
let sibling = nodes
|
||||||
.get(&index.sibling())
|
.get(&index.sibling())
|
||||||
.ok_or(MerkleError::NodeIndexNotFoundInTree(index.sibling()))?;
|
.ok_or(MerkleError::NodeNotInSet(index.sibling()))?;
|
||||||
// get parent hash
|
// get parent hash
|
||||||
let parent = Rpo256::merge(&index.build_node(*node, *sibling));
|
let parent = Rpo256::merge(&index.build_node(*node, *sibling));
|
||||||
|
|
||||||
@@ -185,10 +184,7 @@ impl PartialMerkleTree {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns an error if the specified NodeIndex is not contained in the nodes map.
|
/// Returns an error if the specified NodeIndex is not contained in the nodes map.
|
||||||
pub fn get_node(&self, index: NodeIndex) -> Result<RpoDigest, MerkleError> {
|
pub fn get_node(&self, index: NodeIndex) -> Result<RpoDigest, MerkleError> {
|
||||||
self.nodes
|
self.nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index)).copied()
|
||||||
.get(&index)
|
|
||||||
.ok_or(MerkleError::NodeIndexNotFoundInTree(index))
|
|
||||||
.copied()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if provided index contains in the leaves set, false otherwise.
|
/// Returns true if provided index contains in the leaves set, false otherwise.
|
||||||
@@ -228,7 +224,7 @@ impl PartialMerkleTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.nodes.contains_key(&index) {
|
if !self.nodes.contains_key(&index) {
|
||||||
return Err(MerkleError::NodeIndexNotFoundInTree(index));
|
return Err(MerkleError::NodeNotInSet(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = Vec::new();
|
let mut path = Vec::new();
|
||||||
@@ -339,16 +335,15 @@ impl PartialMerkleTree {
|
|||||||
if self.root() == EMPTY_DIGEST {
|
if self.root() == EMPTY_DIGEST {
|
||||||
self.nodes.insert(ROOT_INDEX, root);
|
self.nodes.insert(ROOT_INDEX, root);
|
||||||
} else if self.root() != root {
|
} else if self.root() != root {
|
||||||
return Err(MerkleError::ConflictingRoots {
|
return Err(MerkleError::ConflictingRoots([self.root(), root].to_vec()));
|
||||||
expected_root: self.root(),
|
|
||||||
actual_root: root,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates value of the leaf at the specified index returning the old leaf value.
|
/// Updates value of the leaf at the specified index returning the old leaf value.
|
||||||
|
/// By default the specified index is assumed to belong to the deepest layer. If the considered
|
||||||
|
/// node does not belong to the tree, the first node on the way to the root will be changed.
|
||||||
///
|
///
|
||||||
/// By default the specified index is assumed to belong to the deepest layer. If the considered
|
/// By default the specified index is assumed to belong to the deepest layer. If the considered
|
||||||
/// node does not belong to the tree, the first node on the way to the root will be changed.
|
/// node does not belong to the tree, the first node on the way to the root will be changed.
|
||||||
@@ -357,7 +352,6 @@ impl PartialMerkleTree {
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns an error if:
|
/// Returns an error if:
|
||||||
/// - No entry exists at the specified index.
|
|
||||||
/// - The specified index is greater than the maximum number of nodes on the deepest layer.
|
/// - The specified index is greater than the maximum number of nodes on the deepest layer.
|
||||||
pub fn update_leaf(&mut self, index: u64, value: Word) -> Result<RpoDigest, MerkleError> {
|
pub fn update_leaf(&mut self, index: u64, value: Word) -> Result<RpoDigest, MerkleError> {
|
||||||
let mut node_index = NodeIndex::new(self.max_depth(), index)?;
|
let mut node_index = NodeIndex::new(self.max_depth(), index)?;
|
||||||
@@ -373,7 +367,7 @@ impl PartialMerkleTree {
|
|||||||
let old_value = self
|
let old_value = self
|
||||||
.nodes
|
.nodes
|
||||||
.insert(node_index, value.into())
|
.insert(node_index, value.into())
|
||||||
.ok_or(MerkleError::NodeIndexNotFoundInTree(node_index))?;
|
.ok_or(MerkleError::NodeNotInSet(node_index))?;
|
||||||
|
|
||||||
// if the old value and new value are the same, there is nothing to update
|
// if the old value and new value are the same, there is nothing to update
|
||||||
if value == *old_value {
|
if value == *old_value {
|
||||||
|
|||||||
@@ -61,10 +61,7 @@ impl MerklePath {
|
|||||||
pub fn verify(&self, index: u64, node: RpoDigest, root: &RpoDigest) -> Result<(), MerkleError> {
|
pub fn verify(&self, index: u64, node: RpoDigest, root: &RpoDigest) -> Result<(), MerkleError> {
|
||||||
let computed_root = self.compute_root(index, node)?;
|
let computed_root = self.compute_root(index, node)?;
|
||||||
if &computed_root != root {
|
if &computed_root != root {
|
||||||
return Err(MerkleError::ConflictingRoots {
|
return Err(MerkleError::ConflictingRoots(vec![computed_root, *root]));
|
||||||
expected_root: *root,
|
|
||||||
actual_root: computed_root,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,39 +1,86 @@
|
|||||||
use thiserror::Error;
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hash::rpo::RpoDigest,
|
hash::rpo::RpoDigest,
|
||||||
merkle::{LeafIndex, SMT_DEPTH},
|
merkle::{LeafIndex, SMT_DEPTH},
|
||||||
|
Word,
|
||||||
};
|
};
|
||||||
|
|
||||||
// SMT LEAF ERROR
|
// SMT LEAF ERROR
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum SmtLeafError {
|
pub enum SmtLeafError {
|
||||||
#[error(
|
InconsistentKeys {
|
||||||
"multiple leaf requires all keys to map to the same leaf index but key1 {key_1} and key2 {key_2} map to different indices"
|
entries: Vec<(RpoDigest, Word)>,
|
||||||
)]
|
key_1: RpoDigest,
|
||||||
InconsistentMultipleLeafKeys { key_1: RpoDigest, key_2: RpoDigest },
|
key_2: RpoDigest,
|
||||||
#[error("single leaf key {key} maps to {actual_leaf_index:?} but was expected to map to {expected_leaf_index:?}")]
|
|
||||||
InconsistentSingleLeafIndices {
|
|
||||||
key: RpoDigest,
|
|
||||||
expected_leaf_index: LeafIndex<SMT_DEPTH>,
|
|
||||||
actual_leaf_index: LeafIndex<SMT_DEPTH>,
|
|
||||||
},
|
},
|
||||||
#[error("supplied leaf index {leaf_index_supplied:?} does not match {leaf_index_from_keys:?} for multiple leaf")]
|
InvalidNumEntriesForMultiple(usize),
|
||||||
InconsistentMultipleLeafIndices {
|
SingleKeyInconsistentWithLeafIndex {
|
||||||
|
key: RpoDigest,
|
||||||
|
leaf_index: LeafIndex<SMT_DEPTH>,
|
||||||
|
},
|
||||||
|
MultipleKeysInconsistentWithLeafIndex {
|
||||||
leaf_index_from_keys: LeafIndex<SMT_DEPTH>,
|
leaf_index_from_keys: LeafIndex<SMT_DEPTH>,
|
||||||
leaf_index_supplied: LeafIndex<SMT_DEPTH>,
|
leaf_index_supplied: LeafIndex<SMT_DEPTH>,
|
||||||
},
|
},
|
||||||
#[error("multiple leaf requires at least two entries but only {0} were given")]
|
}
|
||||||
MultipleLeafRequiresTwoEntries(usize),
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for SmtLeafError {}
|
||||||
|
|
||||||
|
impl fmt::Display for SmtLeafError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use SmtLeafError::*;
|
||||||
|
match self {
|
||||||
|
InvalidNumEntriesForMultiple(num_entries) => {
|
||||||
|
write!(f, "Multiple leaf requires 2 or more entries. Got: {num_entries}")
|
||||||
|
},
|
||||||
|
InconsistentKeys { entries, key_1, key_2 } => {
|
||||||
|
write!(f, "Multiple leaf requires all keys to map to the same leaf index. Offending keys: {key_1} and {key_2}. Entries: {entries:?}.")
|
||||||
|
},
|
||||||
|
SingleKeyInconsistentWithLeafIndex { key, leaf_index } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Single key in leaf inconsistent with leaf index. Key: {key}, leaf index: {}",
|
||||||
|
leaf_index.value()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
MultipleKeysInconsistentWithLeafIndex {
|
||||||
|
leaf_index_from_keys,
|
||||||
|
leaf_index_supplied,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Keys in entries map to leaf index {}, but leaf index {} was supplied",
|
||||||
|
leaf_index_from_keys.value(),
|
||||||
|
leaf_index_supplied.value()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SMT PROOF ERROR
|
// SMT PROOF ERROR
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum SmtProofError {
|
pub enum SmtProofError {
|
||||||
#[error("merkle path length {0} does not match SMT depth {SMT_DEPTH}")]
|
InvalidPathLength(usize),
|
||||||
InvalidMerklePathLength(usize),
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for SmtProofError {}
|
||||||
|
|
||||||
|
impl fmt::Display for SmtProofError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use SmtProofError::*;
|
||||||
|
match self {
|
||||||
|
InvalidPathLength(path_length) => {
|
||||||
|
write!(f, "Invalid Merkle path length. Expected {SMT_DEPTH}, got {path_length}")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,10 @@ impl SmtLeaf {
|
|||||||
1 => {
|
1 => {
|
||||||
let (key, value) = entries[0];
|
let (key, value) = entries[0];
|
||||||
|
|
||||||
let computed_index = LeafIndex::<SMT_DEPTH>::from(key);
|
if LeafIndex::<SMT_DEPTH>::from(key) != leaf_index {
|
||||||
if computed_index != leaf_index {
|
return Err(SmtLeafError::SingleKeyInconsistentWithLeafIndex {
|
||||||
return Err(SmtLeafError::InconsistentSingleLeafIndices {
|
|
||||||
key,
|
key,
|
||||||
expected_leaf_index: leaf_index,
|
leaf_index,
|
||||||
actual_leaf_index: computed_index,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +46,7 @@ impl SmtLeaf {
|
|||||||
// `new_multiple()` checked that all keys map to the same leaf index. We still need
|
// `new_multiple()` checked that all keys map to the same leaf index. We still need
|
||||||
// to ensure that that leaf index is `leaf_index`.
|
// to ensure that that leaf index is `leaf_index`.
|
||||||
if leaf.index() != leaf_index {
|
if leaf.index() != leaf_index {
|
||||||
Err(SmtLeafError::InconsistentMultipleLeafIndices {
|
Err(SmtLeafError::MultipleKeysInconsistentWithLeafIndex {
|
||||||
leaf_index_from_keys: leaf.index(),
|
leaf_index_from_keys: leaf.index(),
|
||||||
leaf_index_supplied: leaf_index,
|
leaf_index_supplied: leaf_index,
|
||||||
})
|
})
|
||||||
@@ -77,7 +75,7 @@ impl SmtLeaf {
|
|||||||
/// - Returns an error if 2 keys in `entries` map to a different leaf index
|
/// - Returns an error if 2 keys in `entries` map to a different leaf index
|
||||||
pub fn new_multiple(entries: Vec<(RpoDigest, Word)>) -> Result<Self, SmtLeafError> {
|
pub fn new_multiple(entries: Vec<(RpoDigest, Word)>) -> Result<Self, SmtLeafError> {
|
||||||
if entries.len() < 2 {
|
if entries.len() < 2 {
|
||||||
return Err(SmtLeafError::MultipleLeafRequiresTwoEntries(entries.len()));
|
return Err(SmtLeafError::InvalidNumEntriesForMultiple(entries.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all keys map to the same leaf index
|
// Check that all keys map to the same leaf index
|
||||||
@@ -91,7 +89,8 @@ impl SmtLeaf {
|
|||||||
let next_leaf_index: LeafIndex<SMT_DEPTH> = next_key.into();
|
let next_leaf_index: LeafIndex<SMT_DEPTH> = next_key.into();
|
||||||
|
|
||||||
if next_leaf_index != first_leaf_index {
|
if next_leaf_index != first_leaf_index {
|
||||||
return Err(SmtLeafError::InconsistentMultipleLeafKeys {
|
return Err(SmtLeafError::InconsistentKeys {
|
||||||
|
entries,
|
||||||
key_1: first_key,
|
key_1: first_key,
|
||||||
key_2: next_key,
|
key_2: next_key,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ impl SmtProof {
|
|||||||
pub fn new(path: MerklePath, leaf: SmtLeaf) -> Result<Self, SmtProofError> {
|
pub fn new(path: MerklePath, leaf: SmtLeaf) -> Result<Self, SmtProofError> {
|
||||||
let depth: usize = SMT_DEPTH.into();
|
let depth: usize = SMT_DEPTH.into();
|
||||||
if path.len() != depth {
|
if path.len() != depth {
|
||||||
return Err(SmtProofError::InvalidMerklePathLength(path.len()));
|
return Err(SmtProofError::InvalidPathLength(path.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { path, leaf })
|
Ok(Self { path, leaf })
|
||||||
|
|||||||
@@ -267,10 +267,7 @@ pub(crate) trait SparseMerkleTree<const DEPTH: u8> {
|
|||||||
// Guard against accidentally trying to apply mutations that were computed against a
|
// Guard against accidentally trying to apply mutations that were computed against a
|
||||||
// different tree, including a stale version of this tree.
|
// different tree, including a stale version of this tree.
|
||||||
if old_root != self.root() {
|
if old_root != self.root() {
|
||||||
return Err(MerkleError::ConflictingRoots {
|
return Err(MerkleError::ConflictingRoots(vec![old_root, self.root()]));
|
||||||
expected_root: self.root(),
|
|
||||||
actual_root: old_root,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, mutation) in node_mutations {
|
for (index, mutation) in node_mutations {
|
||||||
@@ -406,7 +403,7 @@ impl<const DEPTH: u8> TryFrom<NodeIndex> for LeafIndex<DEPTH> {
|
|||||||
|
|
||||||
fn try_from(node_index: NodeIndex) -> Result<Self, Self::Error> {
|
fn try_from(node_index: NodeIndex) -> Result<Self, Self::Error> {
|
||||||
if node_index.depth() != DEPTH {
|
if node_index.depth() != DEPTH {
|
||||||
return Err(MerkleError::InvalidNodeIndexDepth {
|
return Err(MerkleError::InvalidDepth {
|
||||||
expected: DEPTH,
|
expected: DEPTH,
|
||||||
provided: node_index.depth(),
|
provided: node_index.depth(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ impl<const DEPTH: u8> SimpleSmt<DEPTH> {
|
|||||||
|
|
||||||
for (idx, (key, value)) in entries.into_iter().enumerate() {
|
for (idx, (key, value)) in entries.into_iter().enumerate() {
|
||||||
if idx >= max_num_entries {
|
if idx >= max_num_entries {
|
||||||
return Err(MerkleError::TooManyEntries(max_num_entries));
|
return Err(MerkleError::InvalidNumEntries(max_num_entries));
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_value = tree.insert(LeafIndex::<DEPTH>::new(key)?, value);
|
let old_value = tree.insert(LeafIndex::<DEPTH>::new(key)?, value);
|
||||||
@@ -246,7 +246,7 @@ impl<const DEPTH: u8> SimpleSmt<DEPTH> {
|
|||||||
subtree: SimpleSmt<SUBTREE_DEPTH>,
|
subtree: SimpleSmt<SUBTREE_DEPTH>,
|
||||||
) -> Result<RpoDigest, MerkleError> {
|
) -> Result<RpoDigest, MerkleError> {
|
||||||
if SUBTREE_DEPTH > DEPTH {
|
if SUBTREE_DEPTH > DEPTH {
|
||||||
return Err(MerkleError::SubtreeDepthExceedsDepth {
|
return Err(MerkleError::InvalidSubtreeDepth {
|
||||||
subtree_depth: SUBTREE_DEPTH,
|
subtree_depth: SUBTREE_DEPTH,
|
||||||
tree_depth: DEPTH,
|
tree_depth: DEPTH,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use assert_matches::assert_matches;
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{MerkleError, RpoDigest, SimpleSmt},
|
super::{MerkleError, RpoDigest, SimpleSmt},
|
||||||
NodeIndex,
|
NodeIndex,
|
||||||
@@ -259,12 +257,12 @@ fn test_simplesmt_fail_on_duplicates() {
|
|||||||
// consecutive
|
// consecutive
|
||||||
let entries = [(1, *first), (1, *second)];
|
let entries = [(1, *first), (1, *second)];
|
||||||
let smt = SimpleSmt::<64>::with_leaves(entries);
|
let smt = SimpleSmt::<64>::with_leaves(entries);
|
||||||
assert_matches!(smt.unwrap_err(), MerkleError::DuplicateValuesForIndex(1));
|
assert_eq!(smt.unwrap_err(), MerkleError::DuplicateValuesForIndex(1));
|
||||||
|
|
||||||
// not consecutive
|
// not consecutive
|
||||||
let entries = [(1, *first), (5, int_to_leaf(5)), (1, *second)];
|
let entries = [(1, *first), (5, int_to_leaf(5)), (1, *second)];
|
||||||
let smt = SimpleSmt::<64>::with_leaves(entries);
|
let smt = SimpleSmt::<64>::with_leaves(entries);
|
||||||
assert_matches!(smt.unwrap_err(), MerkleError::DuplicateValuesForIndex(1));
|
assert_eq!(smt.unwrap_err(), MerkleError::DuplicateValuesForIndex(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,10 +136,7 @@ impl<T: KvMap<RpoDigest, StoreNode>> MerkleStore<T> {
|
|||||||
self.nodes.get(&hash).ok_or(MerkleError::RootNotInStore(hash))?;
|
self.nodes.get(&hash).ok_or(MerkleError::RootNotInStore(hash))?;
|
||||||
|
|
||||||
for i in (0..index.depth()).rev() {
|
for i in (0..index.depth()).rev() {
|
||||||
let node = self
|
let node = self.nodes.get(&hash).ok_or(MerkleError::NodeNotInStore(hash, index))?;
|
||||||
.nodes
|
|
||||||
.get(&hash)
|
|
||||||
.ok_or(MerkleError::NodeIndexNotFoundInStore(hash, index))?;
|
|
||||||
|
|
||||||
let bit = (index.value() >> i) & 1;
|
let bit = (index.value() >> i) & 1;
|
||||||
hash = if bit == 0 { node.left } else { node.right }
|
hash = if bit == 0 { node.left } else { node.right }
|
||||||
@@ -165,10 +162,7 @@ impl<T: KvMap<RpoDigest, StoreNode>> MerkleStore<T> {
|
|||||||
self.nodes.get(&hash).ok_or(MerkleError::RootNotInStore(hash))?;
|
self.nodes.get(&hash).ok_or(MerkleError::RootNotInStore(hash))?;
|
||||||
|
|
||||||
for i in (0..index.depth()).rev() {
|
for i in (0..index.depth()).rev() {
|
||||||
let node = self
|
let node = self.nodes.get(&hash).ok_or(MerkleError::NodeNotInStore(hash, index))?;
|
||||||
.nodes
|
|
||||||
.get(&hash)
|
|
||||||
.ok_or(MerkleError::NodeIndexNotFoundInStore(hash, index))?;
|
|
||||||
|
|
||||||
let bit = (index.value() >> i) & 1;
|
let bit = (index.value() >> i) & 1;
|
||||||
hash = if bit == 0 {
|
hash = if bit == 0 {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use assert_matches::assert_matches;
|
|
||||||
use seq_macro::seq;
|
use seq_macro::seq;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use {
|
use {
|
||||||
@@ -43,14 +42,14 @@ const VALUES8: [RpoDigest; 8] = [
|
|||||||
fn test_root_not_in_store() -> Result<(), MerkleError> {
|
fn test_root_not_in_store() -> Result<(), MerkleError> {
|
||||||
let mtree = MerkleTree::new(digests_to_words(&VALUES4))?;
|
let mtree = MerkleTree::new(digests_to_words(&VALUES4))?;
|
||||||
let store = MerkleStore::from(&mtree);
|
let store = MerkleStore::from(&mtree);
|
||||||
assert_matches!(
|
assert_eq!(
|
||||||
store.get_node(VALUES4[0], NodeIndex::make(mtree.depth(), 0)),
|
store.get_node(VALUES4[0], NodeIndex::make(mtree.depth(), 0)),
|
||||||
Err(MerkleError::RootNotInStore(root)) if root == VALUES4[0],
|
Err(MerkleError::RootNotInStore(VALUES4[0])),
|
||||||
"Leaf 0 is not a root"
|
"Leaf 0 is not a root"
|
||||||
);
|
);
|
||||||
assert_matches!(
|
assert_eq!(
|
||||||
store.get_path(VALUES4[0], NodeIndex::make(mtree.depth(), 0)),
|
store.get_path(VALUES4[0], NodeIndex::make(mtree.depth(), 0)),
|
||||||
Err(MerkleError::RootNotInStore(root)) if root == VALUES4[0],
|
Err(MerkleError::RootNotInStore(VALUES4[0])),
|
||||||
"Leaf 0 is not a root"
|
"Leaf 0 is not a root"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -65,46 +64,46 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
|||||||
// STORE LEAVES ARE CORRECT -------------------------------------------------------------------
|
// STORE LEAVES ARE CORRECT -------------------------------------------------------------------
|
||||||
// checks the leaves in the store corresponds to the expected values
|
// checks the leaves in the store corresponds to the expected values
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 0)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 0)),
|
||||||
VALUES4[0],
|
Ok(VALUES4[0]),
|
||||||
"node 0 must be in the tree"
|
"node 0 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 1)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 1)),
|
||||||
VALUES4[1],
|
Ok(VALUES4[1]),
|
||||||
"node 1 must be in the tree"
|
"node 1 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 2)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 2)),
|
||||||
VALUES4[2],
|
Ok(VALUES4[2]),
|
||||||
"node 2 must be in the tree"
|
"node 2 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)),
|
||||||
VALUES4[3],
|
Ok(VALUES4[3]),
|
||||||
"node 3 must be in the tree"
|
"node 3 must be in the tree"
|
||||||
);
|
);
|
||||||
|
|
||||||
// STORE LEAVES MATCH TREE --------------------------------------------------------------------
|
// STORE LEAVES MATCH TREE --------------------------------------------------------------------
|
||||||
// sanity check the values returned by the store and the tree
|
// sanity check the values returned by the store and the tree
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_node(NodeIndex::make(mtree.depth(), 0)).unwrap(),
|
mtree.get_node(NodeIndex::make(mtree.depth(), 0)),
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 0)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 0)),
|
||||||
"node 0 must be the same for both MerkleTree and MerkleStore"
|
"node 0 must be the same for both MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_node(NodeIndex::make(mtree.depth(), 1)).unwrap(),
|
mtree.get_node(NodeIndex::make(mtree.depth(), 1)),
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 1)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 1)),
|
||||||
"node 1 must be the same for both MerkleTree and MerkleStore"
|
"node 1 must be the same for both MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_node(NodeIndex::make(mtree.depth(), 2)).unwrap(),
|
mtree.get_node(NodeIndex::make(mtree.depth(), 2)),
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 2)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 2)),
|
||||||
"node 2 must be the same for both MerkleTree and MerkleStore"
|
"node 2 must be the same for both MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_node(NodeIndex::make(mtree.depth(), 3)).unwrap(),
|
mtree.get_node(NodeIndex::make(mtree.depth(), 3)),
|
||||||
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)).unwrap(),
|
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)),
|
||||||
"node 3 must be the same for both MerkleTree and MerkleStore"
|
"node 3 must be the same for both MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -116,8 +115,8 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::make(mtree.depth(), 0)).unwrap(),
|
mtree.get_path(NodeIndex::make(mtree.depth(), 0)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -127,8 +126,8 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::make(mtree.depth(), 1)).unwrap(),
|
mtree.get_path(NodeIndex::make(mtree.depth(), 1)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -138,8 +137,8 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::make(mtree.depth(), 2)).unwrap(),
|
mtree.get_path(NodeIndex::make(mtree.depth(), 2)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -149,8 +148,8 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::make(mtree.depth(), 3)).unwrap(),
|
mtree.get_path(NodeIndex::make(mtree.depth(), 3)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -241,56 +240,56 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
|
|||||||
// STORE LEAVES ARE CORRECT ==============================================================
|
// STORE LEAVES ARE CORRECT ==============================================================
|
||||||
// checks the leaves in the store corresponds to the expected values
|
// checks the leaves in the store corresponds to the expected values
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)),
|
||||||
VALUES4[0],
|
Ok(VALUES4[0]),
|
||||||
"node 0 must be in the tree"
|
"node 0 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)),
|
||||||
VALUES4[1],
|
Ok(VALUES4[1]),
|
||||||
"node 1 must be in the tree"
|
"node 1 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)),
|
||||||
VALUES4[2],
|
Ok(VALUES4[2]),
|
||||||
"node 2 must be in the tree"
|
"node 2 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)),
|
||||||
VALUES4[3],
|
Ok(VALUES4[3]),
|
||||||
"node 3 must be in the tree"
|
"node 3 must be in the tree"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)),
|
||||||
RpoDigest::default(),
|
Ok(RpoDigest::default()),
|
||||||
"unmodified node 4 must be ZERO"
|
"unmodified node 4 must be ZERO"
|
||||||
);
|
);
|
||||||
|
|
||||||
// STORE LEAVES MATCH TREE ===============================================================
|
// STORE LEAVES MATCH TREE ===============================================================
|
||||||
// sanity check the values returned by the store and the tree
|
// sanity check the values returned by the store and the tree
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 0)).unwrap(),
|
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 0)),
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)),
|
||||||
"node 0 must be the same for both SparseMerkleTree and MerkleStore"
|
"node 0 must be the same for both SparseMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 1)).unwrap(),
|
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 1)),
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)),
|
||||||
"node 1 must be the same for both SparseMerkleTree and MerkleStore"
|
"node 1 must be the same for both SparseMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 2)).unwrap(),
|
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 2)),
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)),
|
||||||
"node 2 must be the same for both SparseMerkleTree and MerkleStore"
|
"node 2 must be the same for both SparseMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 3)).unwrap(),
|
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 3)),
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)),
|
||||||
"node 3 must be the same for both SparseMerkleTree and MerkleStore"
|
"node 3 must be the same for both SparseMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 4)).unwrap(),
|
smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 4)),
|
||||||
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)).unwrap(),
|
store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)),
|
||||||
"node 4 must be the same for both SparseMerkleTree and MerkleStore"
|
"node 4 must be the same for both SparseMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -386,46 +385,46 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
|||||||
// STORE LEAVES ARE CORRECT ==============================================================
|
// STORE LEAVES ARE CORRECT ==============================================================
|
||||||
// checks the leaves in the store corresponds to the expected values
|
// checks the leaves in the store corresponds to the expected values
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 0)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 0)),
|
||||||
VALUES4[0],
|
Ok(VALUES4[0]),
|
||||||
"node 0 must be in the pmt"
|
"node 0 must be in the pmt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 1)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 1)),
|
||||||
VALUES4[1],
|
Ok(VALUES4[1]),
|
||||||
"node 1 must be in the pmt"
|
"node 1 must be in the pmt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 2)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 2)),
|
||||||
VALUES4[2],
|
Ok(VALUES4[2]),
|
||||||
"node 2 must be in the pmt"
|
"node 2 must be in the pmt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 3)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 3)),
|
||||||
VALUES4[3],
|
Ok(VALUES4[3]),
|
||||||
"node 3 must be in the pmt"
|
"node 3 must be in the pmt"
|
||||||
);
|
);
|
||||||
|
|
||||||
// STORE LEAVES MATCH PMT ================================================================
|
// STORE LEAVES MATCH PMT ================================================================
|
||||||
// sanity check the values returned by the store and the pmt
|
// sanity check the values returned by the store and the pmt
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_node(NodeIndex::make(pmt.max_depth(), 0)).unwrap(),
|
pmt.get_node(NodeIndex::make(pmt.max_depth(), 0)),
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 0)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 0)),
|
||||||
"node 0 must be the same for both PartialMerkleTree and MerkleStore"
|
"node 0 must be the same for both PartialMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_node(NodeIndex::make(pmt.max_depth(), 1)).unwrap(),
|
pmt.get_node(NodeIndex::make(pmt.max_depth(), 1)),
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 1)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 1)),
|
||||||
"node 1 must be the same for both PartialMerkleTree and MerkleStore"
|
"node 1 must be the same for both PartialMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_node(NodeIndex::make(pmt.max_depth(), 2)).unwrap(),
|
pmt.get_node(NodeIndex::make(pmt.max_depth(), 2)),
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 2)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 2)),
|
||||||
"node 2 must be the same for both PartialMerkleTree and MerkleStore"
|
"node 2 must be the same for both PartialMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_node(NodeIndex::make(pmt.max_depth(), 3)).unwrap(),
|
pmt.get_node(NodeIndex::make(pmt.max_depth(), 3)),
|
||||||
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 3)).unwrap(),
|
store.get_node(pmt.root(), NodeIndex::make(pmt.max_depth(), 3)),
|
||||||
"node 3 must be the same for both PartialMerkleTree and MerkleStore"
|
"node 3 must be the same for both PartialMerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -437,8 +436,8 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_path(NodeIndex::make(pmt.max_depth(), 0)).unwrap(),
|
pmt.get_path(NodeIndex::make(pmt.max_depth(), 0)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -448,8 +447,8 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_path(NodeIndex::make(pmt.max_depth(), 1)).unwrap(),
|
pmt.get_path(NodeIndex::make(pmt.max_depth(), 1)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -459,8 +458,8 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_path(NodeIndex::make(pmt.max_depth(), 2)).unwrap(),
|
pmt.get_path(NodeIndex::make(pmt.max_depth(), 2)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -470,8 +469,8 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
|||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pmt.get_path(NodeIndex::make(pmt.max_depth(), 3)).unwrap(),
|
pmt.get_path(NodeIndex::make(pmt.max_depth(), 3)),
|
||||||
result.path,
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -499,7 +498,7 @@ fn wont_open_to_different_depth_root() {
|
|||||||
let store = MerkleStore::from(&mtree);
|
let store = MerkleStore::from(&mtree);
|
||||||
let index = NodeIndex::root();
|
let index = NodeIndex::root();
|
||||||
let err = store.get_node(root, index).err().unwrap();
|
let err = store.get_node(root, index).err().unwrap();
|
||||||
assert_matches!(err, MerkleError::RootNotInStore(err_root) if err_root == root);
|
assert_eq!(err, MerkleError::RootNotInStore(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -538,7 +537,7 @@ fn test_set_node() -> Result<(), MerkleError> {
|
|||||||
let value = int_to_node(42);
|
let value = int_to_node(42);
|
||||||
let index = NodeIndex::make(mtree.depth(), 0);
|
let index = NodeIndex::make(mtree.depth(), 0);
|
||||||
let new_root = store.set_node(mtree.root(), index, value)?.root;
|
let new_root = store.set_node(mtree.root(), index, value)?.root;
|
||||||
assert_eq!(store.get_node(new_root, index).unwrap(), value, "value must have changed");
|
assert_eq!(store.get_node(new_root, index), Ok(value), "Value must have changed");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -746,7 +745,7 @@ fn get_leaf_depth_works_with_depth_8() {
|
|||||||
// duplicate the tree on `a` and assert the depth is short-circuited by such sub-tree
|
// duplicate the tree on `a` and assert the depth is short-circuited by such sub-tree
|
||||||
let index = NodeIndex::new(8, a).unwrap();
|
let index = NodeIndex::new(8, a).unwrap();
|
||||||
root = store.set_node(root, index, root).unwrap().root;
|
root = store.set_node(root, index, root).unwrap().root;
|
||||||
assert_matches!(store.get_leaf_depth(root, 8, a).unwrap_err(), MerkleError::DepthTooBig(9));
|
assert_eq!(Err(MerkleError::DepthTooBig(9)), store.get_leaf_depth(root, 8, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -145,10 +145,8 @@ impl RandomCoin for RpoRandomCoin {
|
|||||||
self.state[RATE_START] += nonce;
|
self.state[RATE_START] += nonce;
|
||||||
Rpo256::apply_permutation(&mut self.state);
|
Rpo256::apply_permutation(&mut self.state);
|
||||||
|
|
||||||
// reset the buffer and move the next random element pointer to the second rate element.
|
// reset the buffer
|
||||||
// this is done as the first rate element will be "biased" via the provided `nonce` to
|
self.current = RATE_START;
|
||||||
// contain some number of leading zeros.
|
|
||||||
self.current = RATE_START + 1;
|
|
||||||
|
|
||||||
// determine how many bits are needed to represent valid values in the domain
|
// determine how many bits are needed to represent valid values in the domain
|
||||||
let v_mask = (domain_size - 1) as u64;
|
let v_mask = (domain_size - 1) as u64;
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
//! Utilities used in this crate which can also be generally useful downstream.
|
//! Utilities used in this crate which can also be generally useful downstream.
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Display, Write};
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use super::Word;
|
use super::Word;
|
||||||
|
|
||||||
@@ -48,20 +46,36 @@ pub fn bytes_to_hex_string<const N: usize>(data: [u8; N]) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Defines errors which can occur during parsing of hexadecimal strings.
|
/// Defines errors which can occur during parsing of hexadecimal strings.
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug)]
|
||||||
pub enum HexParseError {
|
pub enum HexParseError {
|
||||||
#[error(
|
|
||||||
"expected hex data to have length {expected}, including the 0x prefix, found {actual}"
|
|
||||||
)]
|
|
||||||
InvalidLength { expected: usize, actual: usize },
|
InvalidLength { expected: usize, actual: usize },
|
||||||
#[error("hex encoded data must start with 0x prefix")]
|
|
||||||
MissingPrefix,
|
MissingPrefix,
|
||||||
#[error("hex encoded data must contain only characters [a-zA-Z0-9]")]
|
|
||||||
InvalidChar,
|
InvalidChar,
|
||||||
#[error("hex encoded values of a Digest must be inside the field modulus")]
|
|
||||||
OutOfRange,
|
OutOfRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for HexParseError {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match self {
|
||||||
|
HexParseError::InvalidLength { expected, actual } => {
|
||||||
|
write!(f, "Expected hex data to have length {expected}, including the 0x prefix. Got {actual}")
|
||||||
|
},
|
||||||
|
HexParseError::MissingPrefix => {
|
||||||
|
write!(f, "Hex encoded data must start with 0x prefix")
|
||||||
|
},
|
||||||
|
HexParseError::InvalidChar => {
|
||||||
|
write!(f, "Hex encoded data must contain characters [a-zA-Z0-9]")
|
||||||
|
},
|
||||||
|
HexParseError::OutOfRange => {
|
||||||
|
write!(f, "Hex encoded values of an RpoDigest must be inside the field modulus")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for HexParseError {}
|
||||||
|
|
||||||
/// Parses a hex string into an array of bytes of known size.
|
/// Parses a hex string into an array of bytes of known size.
|
||||||
pub fn hex_to_bytes<const N: usize>(value: &str) -> Result<[u8; N], HexParseError> {
|
pub fn hex_to_bytes<const N: usize>(value: &str) -> Result<[u8; N], HexParseError> {
|
||||||
let expected: usize = (N * 2) + 2;
|
let expected: usize = (N * 2) + 2;
|
||||||
|
|||||||
Reference in New Issue
Block a user