mirror of
https://github.com/arnaucube/miden-crypto.git
synced 2026-01-11 16:41:29 +01:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2a6739605 | ||
|
|
cae87a2790 | ||
|
|
335c50f54d |
@@ -3,6 +3,9 @@
|
|||||||
- Fixed a bug in the implementation of `draw_integers` for `RpoRandomCoin` (#343).
|
- Fixed a bug in the implementation of `draw_integers` for `RpoRandomCoin` (#343).
|
||||||
- [BREAKING] Refactor error messages and use `thiserror` to derive errors (#344).
|
- [BREAKING] Refactor error messages and use `thiserror` to derive errors (#344).
|
||||||
- [BREAKING] Updated Winterfell dependency to v0.11 (#346).
|
- [BREAKING] Updated Winterfell dependency to v0.11 (#346).
|
||||||
|
- Added RPO-STARK based DSA (#349).
|
||||||
|
- Added benchmarks for DSA implementations (#354).
|
||||||
|
- Implemented deterministic RPO-STARK based DSA (#358).
|
||||||
|
|
||||||
## 0.12.0 (2024-10-30)
|
## 0.12.0 (2024-10-30)
|
||||||
|
|
||||||
|
|||||||
209
Cargo.lock
generated
209
Cargo.lock
generated
@@ -113,9 +113,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake3"
|
||||||
version = "1.5.4"
|
version = "1.5.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7"
|
checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@@ -153,9 +153,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.1"
|
version = "1.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
|
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -197,9 +197,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.21"
|
version = "4.5.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -207,9 +207,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.21"
|
version = "4.5.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -231,9 +231,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
@@ -351,19 +351,19 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.9"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
@@ -456,9 +456,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.13"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2"
|
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
@@ -471,10 +471,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.72"
|
version = "0.3.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -495,9 +496,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.164"
|
version = "0.2.168"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
|
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
@@ -525,7 +526,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miden-crypto"
|
name = "miden-crypto"
|
||||||
version = "0.13.0"
|
version = "0.14.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -546,10 +547,13 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"sha3",
|
"sha3",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"winter-air",
|
||||||
"winter-crypto",
|
"winter-crypto",
|
||||||
"winter-math",
|
"winter-math",
|
||||||
|
"winter-prover",
|
||||||
"winter-rand-utils",
|
"winter-rand-utils",
|
||||||
"winter-utils",
|
"winter-utils",
|
||||||
|
"winter-verifier",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -638,6 +642,12 @@ version = "11.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plotters"
|
name = "plotters"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -809,15 +819,15 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.41"
|
version = "0.38.42"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
|
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -855,18 +865,18 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.215"
|
version = "1.0.216"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.215"
|
version = "1.0.216"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -909,9 +919,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.89"
|
version = "2.0.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
|
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -933,18 +943,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.3"
|
version = "2.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
|
checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.3"
|
version = "2.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
|
checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -961,6 +971,34 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
@@ -1018,9 +1056,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -1029,13 +1067,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@@ -1044,9 +1081,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -1054,9 +1091,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1067,15 +1104,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.72"
|
version = "0.3.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -1172,33 +1209,82 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winter-air"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
|
dependencies = [
|
||||||
|
"libm",
|
||||||
|
"winter-crypto",
|
||||||
|
"winter-fri",
|
||||||
|
"winter-math",
|
||||||
|
"winter-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-crypto"
|
name = "winter-crypto"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
checksum = "67c57748fd2da77742be601f03eda639ff6046879738fd1faae86e80018263cb"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake3",
|
"blake3",
|
||||||
|
"rand",
|
||||||
|
"rand_chacha",
|
||||||
"sha3",
|
"sha3",
|
||||||
"winter-math",
|
"winter-math",
|
||||||
"winter-utils",
|
"winter-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winter-fri"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"rand_chacha",
|
||||||
|
"winter-crypto",
|
||||||
|
"winter-math",
|
||||||
|
"winter-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-math"
|
name = "winter-math"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
checksum = "6020c17839fa107ce4a7cc178e407ebbc24adfac1980f4fa2111198e052700ab"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"winter-utils",
|
"winter-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winter-maybe-async"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winter-prover"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"rand_chacha",
|
||||||
|
"tracing",
|
||||||
|
"winter-air",
|
||||||
|
"winter-crypto",
|
||||||
|
"winter-fri",
|
||||||
|
"winter-math",
|
||||||
|
"winter-maybe-async",
|
||||||
|
"winter-rand-utils",
|
||||||
|
"winter-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-rand-utils"
|
name = "winter-rand-utils"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
checksum = "226e4c455f6eb72f64ac6eeb7642df25e21ff2280a4f6b09db75392ad6b390ef"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"winter-utils",
|
"winter-utils",
|
||||||
@@ -1207,8 +1293,19 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "winter-utils"
|
name = "winter-utils"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
checksum = "1507ef312ea5569d54c2c7446a18b82143eb2a2e21f5c3ec7cfbe8200c03bd7c"
|
|
||||||
|
[[package]]
|
||||||
|
name = "winter-verifier"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "git+https://github.com/Al-Kindi-0/winterfell?branch=al-zk#5bafedbc2ba00cf85c6182725754547f6cddafc3"
|
||||||
|
dependencies = [
|
||||||
|
"winter-air",
|
||||||
|
"winter-crypto",
|
||||||
|
"winter-fri",
|
||||||
|
"winter-math",
|
||||||
|
"winter-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
|
|||||||
25
Cargo.toml
25
Cargo.toml
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "miden-crypto"
|
name = "miden-crypto"
|
||||||
version = "0.13.0"
|
version = "0.14.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.14.0"
|
||||||
categories = ["cryptography", "no-std"]
|
categories = ["cryptography", "no-std"]
|
||||||
keywords = ["miden", "crypto", "hash", "merkle"]
|
keywords = ["miden", "crypto", "hash", "merkle"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -19,6 +19,10 @@ bench = false
|
|||||||
doctest = false
|
doctest = false
|
||||||
required-features = ["executable"]
|
required-features = ["executable"]
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "dsa"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "hash"
|
name = "hash"
|
||||||
harness = false
|
harness = false
|
||||||
@@ -63,27 +67,30 @@ std = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
blake3 = { version = "1.5", default-features = false }
|
blake3 = { version = "1.5", default-features = false }
|
||||||
clap = { version = "4.5", optional = true, features = ["derive"] }
|
clap = { version = "4.5", optional = true, features = ["derive"] }
|
||||||
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
num = { version = "0.4", default-features = false, features = ["alloc", "libm"] }
|
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_chacha = { version = "0.3", 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 = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk', optional = true }
|
||||||
rayon = { version = "1.10", optional = true }
|
rayon = { version = "1.10", 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 }
|
thiserror = { version = "2.0", default-features = false }
|
||||||
winter-crypto = { version = "0.11", default-features = false }
|
winter-air = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' }
|
||||||
winter-math = { version = "0.11", default-features = false }
|
winter-crypto = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' }
|
||||||
winter-utils = { version = "0.11", default-features = false }
|
winter-prover = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' }
|
||||||
|
winter-verifier = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' }
|
||||||
|
winter-math = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' }
|
||||||
|
winter-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', branch = 'al-zk' }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = { version = "1.5", default-features = false }
|
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"] }
|
|
||||||
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-utils = {git = 'https://github.com/Al-Kindi-0/winterfell', package = "winter-rand-utils" , branch = 'al-zk' }
|
||||||
rand-utils = { version = "0.11", package = "winter-rand-utils" }
|
|
||||||
seq-macro = { version = "0.3" }
|
seq-macro = { version = "0.3" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# Miden VM Hash Functions
|
# Benchmarks
|
||||||
|
|
||||||
|
## Miden VM Hash Functions
|
||||||
In the Miden VM, we make use of different hash functions. Some of these are "traditional" hash functions, like `BLAKE3`, which are optimized for out-of-STARK performance, while others are algebraic hash functions, like `Rescue Prime`, and are more optimized for a better performance inside the STARK. In what follows, we benchmark several such hash functions and compare against other constructions that are used by other proving systems. More precisely, we benchmark:
|
In the Miden VM, we make use of different hash functions. Some of these are "traditional" hash functions, like `BLAKE3`, which are optimized for out-of-STARK performance, while others are algebraic hash functions, like `Rescue Prime`, and are more optimized for a better performance inside the STARK. In what follows, we benchmark several such hash functions and compare against other constructions that are used by other proving systems. More precisely, we benchmark:
|
||||||
|
|
||||||
* **BLAKE3** as specified [here](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) and implemented [here](https://github.com/BLAKE3-team/BLAKE3) (with a wrapper exposed via this crate).
|
* **BLAKE3** as specified [here](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) and implemented [here](https://github.com/BLAKE3-team/BLAKE3) (with a wrapper exposed via this crate).
|
||||||
@@ -8,13 +10,13 @@ In the Miden VM, we make use of different hash functions. Some of these are "tra
|
|||||||
* **Rescue Prime Optimized (RPO)** as specified [here](https://eprint.iacr.org/2022/1577) and implemented in this crate.
|
* **Rescue Prime Optimized (RPO)** as specified [here](https://eprint.iacr.org/2022/1577) and implemented in this crate.
|
||||||
* **Rescue Prime Extended (RPX)** a variant of the [xHash](https://eprint.iacr.org/2023/1045) hash function as implemented in this crate.
|
* **Rescue Prime Extended (RPX)** a variant of the [xHash](https://eprint.iacr.org/2023/1045) hash function as implemented in this crate.
|
||||||
|
|
||||||
## Comparison and Instructions
|
### Comparison and Instructions
|
||||||
|
|
||||||
### Comparison
|
#### Comparison
|
||||||
We benchmark the above hash functions using two scenarios. The first is a 2-to-1 $(a,b)\mapsto h(a,b)$ hashing where both $a$, $b$ and $h(a,b)$ are the digests corresponding to each of the hash functions.
|
We benchmark the above hash functions using two scenarios. The first is a 2-to-1 $(a,b)\mapsto h(a,b)$ hashing where both $a$, $b$ and $h(a,b)$ are the digests corresponding to each of the hash functions.
|
||||||
The second scenario is that of sequential hashing where we take a sequence of length $100$ field elements and hash these to produce a single digest. The digests are $4$ field elements in a prime field with modulus $2^{64} - 2^{32} + 1$ (i.e., 32 bytes) for Poseidon, Rescue Prime and RPO, and an array `[u8; 32]` for SHA3 and BLAKE3.
|
The second scenario is that of sequential hashing where we take a sequence of length $100$ field elements and hash these to produce a single digest. The digests are $4$ field elements in a prime field with modulus $2^{64} - 2^{32} + 1$ (i.e., 32 bytes) for Poseidon, Rescue Prime and RPO, and an array `[u8; 32]` for SHA3 and BLAKE3.
|
||||||
|
|
||||||
#### Scenario 1: 2-to-1 hashing `h(a,b)`
|
##### Scenario 1: 2-to-1 hashing `h(a,b)`
|
||||||
|
|
||||||
| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 | RPX_256 |
|
| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 | RPX_256 |
|
||||||
| ------------------- | ------ | ------- | --------- | --------- | ------- | ------- |
|
| ------------------- | ------ | ------- | --------- | --------- | ------- | ------- |
|
||||||
@@ -26,7 +28,7 @@ The second scenario is that of sequential hashing where we take a sequence of le
|
|||||||
| Intel Core i5-8279U | 68 ns | 536 ns | 2.0 µs | 13.6 µs | 8.5 µs | 4.4 µs |
|
| Intel Core i5-8279U | 68 ns | 536 ns | 2.0 µs | 13.6 µs | 8.5 µs | 4.4 µs |
|
||||||
| Intel Xeon 8375C | 67 ns | | | | 8.2 µs | |
|
| Intel Xeon 8375C | 67 ns | | | | 8.2 µs | |
|
||||||
|
|
||||||
#### Scenario 2: Sequential hashing of 100 elements `h([a_0,...,a_99])`
|
##### Scenario 2: Sequential hashing of 100 elements `h([a_0,...,a_99])`
|
||||||
|
|
||||||
| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 | RPX_256 |
|
| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 | RPX_256 |
|
||||||
| ------------------- | -------| ------- | --------- | --------- | ------- | ------- |
|
| ------------------- | -------| ------- | --------- | --------- | ------- | ------- |
|
||||||
@@ -42,7 +44,7 @@ Notes:
|
|||||||
- On Graviton 3, RPO256 and RPX256 are run with SVE acceleration enabled.
|
- On Graviton 3, RPO256 and RPX256 are run with SVE acceleration enabled.
|
||||||
- On AMD EPYC 9R14, RPO256 and RPX256 are run with AVX2 acceleration enabled.
|
- On AMD EPYC 9R14, RPO256 and RPX256 are run with AVX2 acceleration enabled.
|
||||||
|
|
||||||
### Instructions
|
#### Instructions
|
||||||
Before you can run the benchmarks, you'll need to make sure you have Rust [installed](https://www.rust-lang.org/tools/install). After that, to run the benchmarks for RPO and BLAKE3, clone the current repository, and from the root directory of the repo run the following:
|
Before you can run the benchmarks, you'll need to make sure you have Rust [installed](https://www.rust-lang.org/tools/install). After that, to run the benchmarks for RPO and BLAKE3, clone the current repository, and from the root directory of the repo run the following:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -54,3 +56,47 @@ To run the benchmarks for Rescue Prime, Poseidon and SHA3, clone the following [
|
|||||||
```
|
```
|
||||||
cargo bench hash
|
cargo bench hash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Miden VM DSA
|
||||||
|
|
||||||
|
We make use of the following digital signature algorithms (DSA) in the Miden VM:
|
||||||
|
|
||||||
|
* **RPO-Falcon512** as specified [here](https://falcon-sign.info/falcon.pdf) with the one difference being the use of the RPO hash function for the hash-to-point algorithm (Algorithm 3 in the previous reference) instead of SHAKE256.
|
||||||
|
* **RPO-STARK** as specified [here](https://eprint.iacr.org/2024/1553), where the parameters are the ones for the unique-decoding regime (UDR) with the two differences:
|
||||||
|
* We rely on Conjecture 1 in the [ethSTARK](https://eprint.iacr.org/2021/582) paper.
|
||||||
|
* The number of FRI queries is $30$ and the grinding factor is $12$ bits. Thus using the previous point we can argue that the modified version achieves at least $102$ bits of average-case existential unforgeability security against $2^{113}$-query bound adversaries that can obtain up to $2^{64}$ signatures under the same public key.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Comparison and Instructions
|
||||||
|
|
||||||
|
#### Comparison
|
||||||
|
|
||||||
|
|
||||||
|
##### Key Generation
|
||||||
|
|
||||||
|
| DSA | RPO-Falcon512 | RPO-STARK |
|
||||||
|
| ------------------- | :-----------: | :-------: |
|
||||||
|
| Apple M1 Pro | 590 ms | 6 µs |
|
||||||
|
| Intel Core i5-8279U | 585 ms | 10 µs |
|
||||||
|
|
||||||
|
##### Signature Generation
|
||||||
|
|
||||||
|
| DSA | RPO-Falcon512 | RPO-STARK |
|
||||||
|
| ------------------- | :-----------: | :-------: |
|
||||||
|
| Apple M1 Pro | 1.5 ms | 78 ms |
|
||||||
|
| Intel Core i5-8279U | 1.8 ms | 130 ms |
|
||||||
|
|
||||||
|
##### Signature Verification
|
||||||
|
|
||||||
|
| DSA | RPO-Falcon512 | RPO-STARK |
|
||||||
|
| ------------------- | :-----------: | :-------: |
|
||||||
|
| Apple M1 Pro | 0.7 ms | 4.5 ms |
|
||||||
|
| Intel Core i5-8279U | 1.2 ms | 7.9 ms |
|
||||||
|
|
||||||
|
#### Instructions
|
||||||
|
Before you can run the benchmarks, you'll need to make sure you have Rust [installed](https://www.rust-lang.org/tools/install). After that, to run the benchmarks, clone the current repository, and from the root directory of the repo run the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo bench --bench dsa
|
||||||
|
```
|
||||||
88
benches/dsa.rs
Normal file
88
benches/dsa.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||||
|
use miden_crypto::dsa::{
|
||||||
|
rpo_falcon512::SecretKey as FalconSecretKey, rpo_stark::SecretKey as RpoStarkSecretKey,
|
||||||
|
};
|
||||||
|
use rand_utils::rand_array;
|
||||||
|
|
||||||
|
fn key_gen_falcon(c: &mut Criterion) {
|
||||||
|
c.bench_function("Falcon public key generation", |bench| {
|
||||||
|
bench.iter_batched(|| FalconSecretKey::new(), |sk| sk.public_key(), BatchSize::SmallInput)
|
||||||
|
});
|
||||||
|
|
||||||
|
c.bench_function("Falcon secret key generation", |bench| {
|
||||||
|
bench.iter_batched(|| {}, |_| FalconSecretKey::new(), BatchSize::SmallInput)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_gen_rpo_stark(c: &mut Criterion) {
|
||||||
|
c.bench_function("RPO-STARK public key generation", |bench| {
|
||||||
|
bench.iter_batched(
|
||||||
|
|| RpoStarkSecretKey::random(),
|
||||||
|
|sk| sk.public_key(),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
c.bench_function("RPO-STARK secret key generation", |bench| {
|
||||||
|
bench.iter_batched(|| {}, |_| RpoStarkSecretKey::random(), BatchSize::SmallInput)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature_gen_falcon(c: &mut Criterion) {
|
||||||
|
c.bench_function("Falcon signature generation", |bench| {
|
||||||
|
bench.iter_batched(
|
||||||
|
|| (FalconSecretKey::new(), rand_array().into()),
|
||||||
|
|(sk, msg)| sk.sign(msg),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature_gen_rpo_stark(c: &mut Criterion) {
|
||||||
|
c.bench_function("RPO-STARK signature generation", |bench| {
|
||||||
|
bench.iter_batched(
|
||||||
|
|| (RpoStarkSecretKey::random(), rand_array().into()),
|
||||||
|
|(sk, msg)| sk.sign(msg),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature_ver_falcon(c: &mut Criterion) {
|
||||||
|
c.bench_function("Falcon signature verification", |bench| {
|
||||||
|
bench.iter_batched(
|
||||||
|
|| {
|
||||||
|
let sk = FalconSecretKey::new();
|
||||||
|
let msg = rand_array().into();
|
||||||
|
(sk.public_key(), msg, sk.sign(msg))
|
||||||
|
},
|
||||||
|
|(pk, msg, sig)| pk.verify(msg, &sig),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature_ver_rpo_stark(c: &mut Criterion) {
|
||||||
|
c.bench_function("RPO-STARK signature verification", |bench| {
|
||||||
|
bench.iter_batched(
|
||||||
|
|| {
|
||||||
|
let sk = RpoStarkSecretKey::random();
|
||||||
|
let msg = rand_array().into();
|
||||||
|
(sk.public_key(), msg, sk.sign(msg))
|
||||||
|
},
|
||||||
|
|(pk, msg, sig)| pk.verify(msg, &sig),
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(
|
||||||
|
dsa_group,
|
||||||
|
key_gen_falcon,
|
||||||
|
key_gen_rpo_stark,
|
||||||
|
signature_gen_falcon,
|
||||||
|
signature_gen_rpo_stark,
|
||||||
|
signature_ver_falcon,
|
||||||
|
signature_ver_rpo_stark
|
||||||
|
);
|
||||||
|
criterion_main!(dsa_group);
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
//! Digital signature schemes supported by default in the Miden VM.
|
//! Digital signature schemes supported by default in the Miden VM.
|
||||||
|
|
||||||
pub mod rpo_falcon512;
|
pub mod rpo_falcon512;
|
||||||
|
|
||||||
|
pub mod rpo_stark;
|
||||||
|
|||||||
24
src/dsa/rpo_stark/mod.rs
Normal file
24
src/dsa/rpo_stark/mod.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
mod signature;
|
||||||
|
pub use signature::{PublicKey, SecretKey, Signature};
|
||||||
|
|
||||||
|
mod stark;
|
||||||
|
pub use stark::{PublicInputs, RescueAir};
|
||||||
|
|
||||||
|
// TESTS
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::SecretKey;
|
||||||
|
use crate::Word;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_signature() {
|
||||||
|
let sk = SecretKey::new(Word::default());
|
||||||
|
|
||||||
|
let message = Word::default();
|
||||||
|
let signature = sk.sign(message);
|
||||||
|
let pk = sk.public_key();
|
||||||
|
assert!(pk.verify(message, &signature))
|
||||||
|
}
|
||||||
|
}
|
||||||
173
src/dsa/rpo_stark/signature/mod.rs
Normal file
173
src/dsa/rpo_stark/signature/mod.rs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
use rand::{distributions::Uniform, prelude::Distribution, Rng};
|
||||||
|
use winter_air::{FieldExtension, ProofOptions};
|
||||||
|
use winter_math::{fields::f64::BaseElement, FieldElement};
|
||||||
|
use winter_prover::Proof;
|
||||||
|
use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
dsa::rpo_stark::stark::RpoSignatureScheme,
|
||||||
|
hash::{rpo::Rpo256, DIGEST_SIZE},
|
||||||
|
StarkField, Word, ZERO,
|
||||||
|
};
|
||||||
|
|
||||||
|
// CONSTANTS
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// Specifies the parameters of the STARK underlying the signature scheme. These parameters provide
|
||||||
|
/// at least 102 bits of security under the conjectured security of the toy protocol in
|
||||||
|
/// the ethSTARK paper [1].
|
||||||
|
///
|
||||||
|
/// [1]: https://eprint.iacr.org/2021/582
|
||||||
|
pub const PROOF_OPTIONS: ProofOptions =
|
||||||
|
ProofOptions::new(30, 8, 12, FieldExtension::Quadratic, 4, 7, true);
|
||||||
|
|
||||||
|
// PUBLIC KEY
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// A public key for verifying signatures.
|
||||||
|
///
|
||||||
|
/// The public key is a [Word] (i.e., 4 field elements) that is the hash of the secret key.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct PublicKey(Word);
|
||||||
|
|
||||||
|
impl PublicKey {
|
||||||
|
/// Returns the [Word] defining the public key.
|
||||||
|
pub fn inner(&self) -> Word {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PublicKey {
|
||||||
|
/// Verifies the provided signature against provided message and this public key.
|
||||||
|
pub fn verify(&self, message: Word, signature: &Signature) -> bool {
|
||||||
|
signature.verify(message, *self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for PublicKey {
|
||||||
|
fn write_into<W: ByteWriter>(&self, target: &mut W) {
|
||||||
|
self.0.write_into(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserializable for PublicKey {
|
||||||
|
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
|
||||||
|
let pk = <Word>::read_from(source)?;
|
||||||
|
Ok(Self(pk))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SECRET KEY
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// A secret key for generating signatures.
|
||||||
|
///
|
||||||
|
/// The secret key is a [Word] (i.e., 4 field elements).
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct SecretKey(Word);
|
||||||
|
|
||||||
|
impl SecretKey {
|
||||||
|
/// Generates a secret key from OS-provided randomness.
|
||||||
|
pub fn new(word: Word) -> Self {
|
||||||
|
Self(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a secret key from a [Word].
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn random() -> Self {
|
||||||
|
use rand::{rngs::StdRng, SeedableRng};
|
||||||
|
|
||||||
|
let mut rng = StdRng::from_entropy();
|
||||||
|
Self::with_rng(&mut rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a secret_key using the provided random number generator `Rng`.
|
||||||
|
pub fn with_rng<R: Rng>(rng: &mut R) -> Self {
|
||||||
|
let mut sk = [ZERO; 4];
|
||||||
|
let uni_dist = Uniform::from(0..BaseElement::MODULUS);
|
||||||
|
|
||||||
|
for s in sk.iter_mut() {
|
||||||
|
let sampled_integer = uni_dist.sample(rng);
|
||||||
|
*s = BaseElement::new(sampled_integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self(sk)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the public key corresponding to this secret key.
|
||||||
|
pub fn public_key(&self) -> PublicKey {
|
||||||
|
let mut elements = [BaseElement::ZERO; 8];
|
||||||
|
elements[..DIGEST_SIZE].copy_from_slice(&self.0);
|
||||||
|
let pk = Rpo256::hash_elements(&elements);
|
||||||
|
PublicKey(pk.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signs a message with this secret key.
|
||||||
|
pub fn sign(&self, message: Word) -> Signature {
|
||||||
|
let signature: RpoSignatureScheme<Rpo256> = RpoSignatureScheme::new(PROOF_OPTIONS);
|
||||||
|
let proof = signature.sign(self.0, message);
|
||||||
|
Signature { proof }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for SecretKey {
|
||||||
|
fn write_into<W: ByteWriter>(&self, target: &mut W) {
|
||||||
|
self.0.write_into(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserializable for SecretKey {
|
||||||
|
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
|
||||||
|
let sk = <Word>::read_from(source)?;
|
||||||
|
Ok(Self(sk))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIGNATURE
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// An RPO STARK-based signature over a message.
|
||||||
|
///
|
||||||
|
/// The signature is a STARK proof of knowledge of a pre-image given an image where the map is
|
||||||
|
/// the RPO permutation, the pre-image is the secret key and the image is the public key.
|
||||||
|
/// The current implementation follows the description in [1] but relies on the conjectured security
|
||||||
|
/// of the toy protocol in the ethSTARK paper [2], which gives us using the parameter set
|
||||||
|
/// given in `PROOF_OPTIONS` a signature with $102$ bits of average-case existential unforgeability
|
||||||
|
/// security against $2^{113}$-query bound adversaries that can obtain up to $2^{64}$ signatures
|
||||||
|
/// under the same public key.
|
||||||
|
///
|
||||||
|
/// [1]: https://eprint.iacr.org/2024/1553
|
||||||
|
/// [2]: https://eprint.iacr.org/2021/582
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Signature {
|
||||||
|
proof: Proof,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signature {
|
||||||
|
/// Returns the STARK proof constituting the signature.
|
||||||
|
pub fn inner(&self) -> Proof {
|
||||||
|
self.proof.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this signature is a valid signature for the specified message generated
|
||||||
|
/// against the secret key matching the specified public key.
|
||||||
|
pub fn verify(&self, message: Word, pk: PublicKey) -> bool {
|
||||||
|
let signature: RpoSignatureScheme<Rpo256> = RpoSignatureScheme::new(PROOF_OPTIONS);
|
||||||
|
|
||||||
|
let res = signature.verify(pk.inner(), message, self.proof.clone());
|
||||||
|
res.is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for Signature {
|
||||||
|
fn write_into<W: ByteWriter>(&self, target: &mut W) {
|
||||||
|
self.proof.write_into(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserializable for Signature {
|
||||||
|
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
|
||||||
|
let proof = Proof::read_from(source)?;
|
||||||
|
Ok(Self { proof })
|
||||||
|
}
|
||||||
|
}
|
||||||
198
src/dsa/rpo_stark/stark/air.rs
Normal file
198
src/dsa/rpo_stark/stark/air.rs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use winter_math::{fields::f64::BaseElement, FieldElement, ToElements};
|
||||||
|
use winter_prover::{
|
||||||
|
Air, AirContext, Assertion, EvaluationFrame, ProofOptions, TraceInfo,
|
||||||
|
TransitionConstraintDegree,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
hash::{ARK1, ARK2, MDS, STATE_WIDTH},
|
||||||
|
Word, ZERO,
|
||||||
|
};
|
||||||
|
|
||||||
|
// CONSTANTS
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
pub const HASH_CYCLE_LEN: usize = 8;
|
||||||
|
|
||||||
|
// AIR
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
pub struct RescueAir {
|
||||||
|
context: AirContext<BaseElement>,
|
||||||
|
pub_key: Word,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Air for RescueAir {
|
||||||
|
type BaseField = BaseElement;
|
||||||
|
type PublicInputs = PublicInputs;
|
||||||
|
|
||||||
|
type GkrProof = ();
|
||||||
|
type GkrVerifier = ();
|
||||||
|
|
||||||
|
// CONSTRUCTOR
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: ProofOptions) -> Self {
|
||||||
|
let degrees = vec![
|
||||||
|
// Apply RPO rounds.
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
TransitionConstraintDegree::new(7),
|
||||||
|
];
|
||||||
|
assert_eq!(STATE_WIDTH, trace_info.width());
|
||||||
|
let context = AirContext::new(trace_info, degrees, 12, options);
|
||||||
|
let context = context.set_num_transition_exemptions(1);
|
||||||
|
RescueAir { context, pub_key: pub_inputs.pub_key }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context(&self) -> &AirContext<Self::BaseField> {
|
||||||
|
&self.context
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evaluate_transition<E: FieldElement + From<Self::BaseField>>(
|
||||||
|
&self,
|
||||||
|
frame: &EvaluationFrame<E>,
|
||||||
|
periodic_values: &[E],
|
||||||
|
result: &mut [E],
|
||||||
|
) {
|
||||||
|
let current = frame.current();
|
||||||
|
let next = frame.next();
|
||||||
|
// expected state width is 12 field elements
|
||||||
|
debug_assert_eq!(STATE_WIDTH, current.len());
|
||||||
|
debug_assert_eq!(STATE_WIDTH, next.len());
|
||||||
|
|
||||||
|
enforce_rpo_round(frame, result, periodic_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_assertions(&self) -> Vec<Assertion<Self::BaseField>> {
|
||||||
|
let initial_step = 0;
|
||||||
|
let last_step = self.trace_length() - 1;
|
||||||
|
vec![
|
||||||
|
// Assert that the capacity as well as the second half of the rate portion of the state
|
||||||
|
// are initialized to `ZERO`.The first half of the rate is unconstrained as it will
|
||||||
|
// contain the secret key
|
||||||
|
Assertion::single(0, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(1, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(2, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(3, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(8, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(9, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(10, initial_step, Self::BaseField::ZERO),
|
||||||
|
Assertion::single(11, initial_step, Self::BaseField::ZERO),
|
||||||
|
// Assert that the public key is the correct one
|
||||||
|
Assertion::single(4, last_step, self.pub_key[0]),
|
||||||
|
Assertion::single(5, last_step, self.pub_key[1]),
|
||||||
|
Assertion::single(6, last_step, self.pub_key[2]),
|
||||||
|
Assertion::single(7, last_step, self.pub_key[3]),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_periodic_column_values(&self) -> Vec<Vec<Self::BaseField>> {
|
||||||
|
get_round_constants()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PublicInputs {
|
||||||
|
pub(crate) pub_key: Word,
|
||||||
|
pub(crate) msg: Word,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PublicInputs {
|
||||||
|
pub fn new(pub_key: Word, msg: Word) -> Self {
|
||||||
|
Self { pub_key, msg }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToElements<BaseElement> for PublicInputs {
|
||||||
|
fn to_elements(&self) -> Vec<BaseElement> {
|
||||||
|
let mut res = self.pub_key.to_vec();
|
||||||
|
res.extend_from_slice(self.msg.as_ref());
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HELPER EVALUATORS
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Enforces constraints for a single round of the Rescue Prime Optimized hash functions.
|
||||||
|
pub fn enforce_rpo_round<E: FieldElement + From<BaseElement>>(
|
||||||
|
frame: &EvaluationFrame<E>,
|
||||||
|
result: &mut [E],
|
||||||
|
ark: &[E],
|
||||||
|
) {
|
||||||
|
// compute the state that should result from applying the first 5 operations of the RPO round to
|
||||||
|
// the current hash state.
|
||||||
|
let mut step1 = [E::ZERO; STATE_WIDTH];
|
||||||
|
step1.copy_from_slice(frame.current());
|
||||||
|
|
||||||
|
apply_mds(&mut step1);
|
||||||
|
// add constants
|
||||||
|
for i in 0..STATE_WIDTH {
|
||||||
|
step1[i] += ark[i];
|
||||||
|
}
|
||||||
|
apply_sbox(&mut step1);
|
||||||
|
apply_mds(&mut step1);
|
||||||
|
// add constants
|
||||||
|
for i in 0..STATE_WIDTH {
|
||||||
|
step1[i] += ark[STATE_WIDTH + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the state that should result from applying the inverse of the last operation of the
|
||||||
|
// RPO round to the next step of the computation.
|
||||||
|
let mut step2 = [E::ZERO; STATE_WIDTH];
|
||||||
|
step2.copy_from_slice(frame.next());
|
||||||
|
apply_sbox(&mut step2);
|
||||||
|
|
||||||
|
// make sure that the results are equal.
|
||||||
|
for i in 0..STATE_WIDTH {
|
||||||
|
result[i] = step2[i] - step1[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn apply_sbox<E: FieldElement + From<BaseElement>>(state: &mut [E; STATE_WIDTH]) {
|
||||||
|
state.iter_mut().for_each(|v| {
|
||||||
|
let t2 = v.square();
|
||||||
|
let t4 = t2.square();
|
||||||
|
*v *= t2 * t4;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn apply_mds<E: FieldElement + From<BaseElement>>(state: &mut [E; STATE_WIDTH]) {
|
||||||
|
let mut result = [E::ZERO; STATE_WIDTH];
|
||||||
|
result.iter_mut().zip(MDS).for_each(|(r, mds_row)| {
|
||||||
|
state.iter().zip(mds_row).for_each(|(&s, m)| {
|
||||||
|
*r += E::from(m) * s;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
*state = result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns RPO round constants arranged in column-major form.
|
||||||
|
pub fn get_round_constants() -> Vec<Vec<BaseElement>> {
|
||||||
|
let mut constants = Vec::new();
|
||||||
|
for _ in 0..(STATE_WIDTH * 2) {
|
||||||
|
constants.push(vec![ZERO; HASH_CYCLE_LEN]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
|
for i in 0..HASH_CYCLE_LEN - 1 {
|
||||||
|
for j in 0..STATE_WIDTH {
|
||||||
|
constants[j][i] = ARK1[i][j];
|
||||||
|
constants[j + STATE_WIDTH][i] = ARK2[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constants
|
||||||
|
}
|
||||||
98
src/dsa/rpo_stark/stark/mod.rs
Normal file
98
src/dsa/rpo_stark/stark/mod.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use prover::RpoSignatureProver;
|
||||||
|
use rand_chacha::ChaCha20Rng;
|
||||||
|
use winter_crypto::{ElementHasher, SaltedMerkleTree};
|
||||||
|
use winter_math::fields::f64::BaseElement;
|
||||||
|
use winter_prover::{Proof, ProofOptions, Prover};
|
||||||
|
use winter_utils::Serializable;
|
||||||
|
use winter_verifier::{verify, AcceptableOptions, VerifierError};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
hash::{rpo::Rpo256, DIGEST_SIZE},
|
||||||
|
rand::RpoRandomCoin,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod air;
|
||||||
|
pub use air::{PublicInputs, RescueAir};
|
||||||
|
mod prover;
|
||||||
|
|
||||||
|
/// Represents an abstract STARK-based signature scheme with knowledge of RPO pre-image as
|
||||||
|
/// the hard relation.
|
||||||
|
pub struct RpoSignatureScheme<H: ElementHasher> {
|
||||||
|
options: ProofOptions,
|
||||||
|
_h: PhantomData<H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: ElementHasher<BaseField = BaseElement> + Sync> RpoSignatureScheme<H> {
|
||||||
|
pub fn new(options: ProofOptions) -> Self {
|
||||||
|
RpoSignatureScheme { options, _h: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(&self, sk: [BaseElement; DIGEST_SIZE], msg: [BaseElement; DIGEST_SIZE]) -> Proof {
|
||||||
|
// create a prover
|
||||||
|
let prover = RpoSignatureProver::<H>::new(msg, self.options.clone());
|
||||||
|
|
||||||
|
// generate execution trace
|
||||||
|
let trace = prover.build_trace(sk);
|
||||||
|
|
||||||
|
// generate the initial seed for the PRNG used for zero-knowledge
|
||||||
|
let seed: [u8; 32] = generate_seed(sk, msg);
|
||||||
|
|
||||||
|
// generate the proof
|
||||||
|
prover.prove(trace, Some(seed)).expect("failed to generate the signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
pub_key: [BaseElement; DIGEST_SIZE],
|
||||||
|
msg: [BaseElement; DIGEST_SIZE],
|
||||||
|
proof: Proof,
|
||||||
|
) -> Result<(), VerifierError> {
|
||||||
|
// we make sure that the parameters used in generating the proof match the expected ones
|
||||||
|
if *proof.options() != self.options {
|
||||||
|
return Err(VerifierError::UnacceptableProofOptions);
|
||||||
|
}
|
||||||
|
let pub_inputs = PublicInputs { pub_key, msg };
|
||||||
|
let acceptable_options = AcceptableOptions::OptionSet(vec![proof.options().clone()]);
|
||||||
|
verify::<RescueAir, Rpo256, RpoRandomCoin, SaltedMerkleTree<Rpo256, ChaCha20Rng>>(
|
||||||
|
proof,
|
||||||
|
pub_inputs,
|
||||||
|
&acceptable_options,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deterministically generates a seed for seeding the PRNG used for zero-knowledge.
|
||||||
|
///
|
||||||
|
/// This uses the argument described in [RFC 6979](https://datatracker.ietf.org/doc/html/rfc6979#section-3.5)
|
||||||
|
/// § 3.5 where the concatenation of the private key and the hashed message, i.e., sk || H(m), is
|
||||||
|
/// used in order to construct the initial seed of a PRNG.
|
||||||
|
///
|
||||||
|
/// Note that we hash in also a context string in order to domain separate between different
|
||||||
|
/// instantiations of the signature scheme.
|
||||||
|
#[inline]
|
||||||
|
pub fn generate_seed(sk: [BaseElement; DIGEST_SIZE], msg: [BaseElement; DIGEST_SIZE]) -> [u8; 32] {
|
||||||
|
let context_bytes = "
|
||||||
|
Seed for PRNG used for Zero-knowledge in RPO-STARK signature scheme:
|
||||||
|
1. Version: Conjectured security
|
||||||
|
2. FRI queries: 30
|
||||||
|
3. Blowup factor: 8
|
||||||
|
4. Grinding bits: 12
|
||||||
|
5. Field extension degree: 2
|
||||||
|
6. FRI folding factor: 4
|
||||||
|
7. FRI remainder polynomial max degree: 7
|
||||||
|
"
|
||||||
|
.to_bytes();
|
||||||
|
let sk_bytes = sk.to_bytes();
|
||||||
|
let msg_bytes = msg.to_bytes();
|
||||||
|
|
||||||
|
let total_length = context_bytes.len() + sk_bytes.len() + msg_bytes.len();
|
||||||
|
let mut buffer = Vec::with_capacity(total_length);
|
||||||
|
buffer.extend_from_slice(&context_bytes);
|
||||||
|
buffer.extend_from_slice(&sk_bytes);
|
||||||
|
buffer.extend_from_slice(&msg_bytes);
|
||||||
|
|
||||||
|
blake3::hash(&buffer).into()
|
||||||
|
}
|
||||||
148
src/dsa/rpo_stark/stark/prover.rs
Normal file
148
src/dsa/rpo_stark/stark/prover.rs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use rand_chacha::ChaCha20Rng;
|
||||||
|
use winter_air::{
|
||||||
|
AuxRandElements, ConstraintCompositionCoefficients, PartitionOptions, ZkParameters,
|
||||||
|
};
|
||||||
|
use winter_crypto::{ElementHasher, SaltedMerkleTree};
|
||||||
|
use winter_math::{fields::f64::BaseElement, FieldElement};
|
||||||
|
use winter_prover::{
|
||||||
|
matrix::ColMatrix, CompositionPoly, CompositionPolyTrace, DefaultConstraintCommitment,
|
||||||
|
DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, StarkDomain, Trace,
|
||||||
|
TraceInfo, TracePolyTable, TraceTable,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN};
|
||||||
|
use crate::{
|
||||||
|
hash::{rpo::Rpo256, STATE_WIDTH},
|
||||||
|
rand::RpoRandomCoin,
|
||||||
|
Word, ZERO,
|
||||||
|
};
|
||||||
|
|
||||||
|
// PROVER
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// A prover for the RPO STARK-based signature scheme.
|
||||||
|
///
|
||||||
|
/// The signature is based on the the one-wayness of the RPO hash function but it is generic over
|
||||||
|
/// the hash function used for instantiating the random oracle for the BCS transform.
|
||||||
|
pub(crate) struct RpoSignatureProver<H: ElementHasher + Sync> {
|
||||||
|
message: Word,
|
||||||
|
options: ProofOptions,
|
||||||
|
_hasher: PhantomData<H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: ElementHasher + Sync> RpoSignatureProver<H> {
|
||||||
|
pub(crate) fn new(message: Word, options: ProofOptions) -> Self {
|
||||||
|
Self { message, options, _hasher: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build_trace(&self, sk: Word) -> TraceTable<BaseElement> {
|
||||||
|
let mut trace = TraceTable::new(STATE_WIDTH, HASH_CYCLE_LEN);
|
||||||
|
|
||||||
|
trace.fill(
|
||||||
|
|state| {
|
||||||
|
// initialize first half of the rate portion of the state with the secret key
|
||||||
|
state[0] = ZERO;
|
||||||
|
state[1] = ZERO;
|
||||||
|
state[2] = ZERO;
|
||||||
|
state[3] = ZERO;
|
||||||
|
state[4] = sk[0];
|
||||||
|
state[5] = sk[1];
|
||||||
|
state[6] = sk[2];
|
||||||
|
state[7] = sk[3];
|
||||||
|
state[8] = ZERO;
|
||||||
|
state[9] = ZERO;
|
||||||
|
state[10] = ZERO;
|
||||||
|
state[11] = ZERO;
|
||||||
|
},
|
||||||
|
|step, state| {
|
||||||
|
Rpo256::apply_round(
|
||||||
|
state.try_into().expect("should not fail given the size of the array"),
|
||||||
|
step,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
trace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: ElementHasher> Prover for RpoSignatureProver<H>
|
||||||
|
where
|
||||||
|
H: ElementHasher<BaseField = BaseElement> + Sync,
|
||||||
|
{
|
||||||
|
type BaseField = BaseElement;
|
||||||
|
type Air = RescueAir;
|
||||||
|
type Trace = TraceTable<BaseElement>;
|
||||||
|
type HashFn = Rpo256;
|
||||||
|
type VC = SaltedMerkleTree<Self::HashFn, Self::ZkPrng>;
|
||||||
|
type RandomCoin = RpoRandomCoin;
|
||||||
|
type TraceLde<E: FieldElement<BaseField = Self::BaseField>> =
|
||||||
|
DefaultTraceLde<E, Self::HashFn, Self::VC>;
|
||||||
|
type ConstraintCommitment<E: FieldElement<BaseField = Self::BaseField>> =
|
||||||
|
DefaultConstraintCommitment<E, Self::HashFn, Self::ZkPrng, Self::VC>;
|
||||||
|
type ConstraintEvaluator<'a, E: FieldElement<BaseField = Self::BaseField>> =
|
||||||
|
DefaultConstraintEvaluator<'a, Self::Air, E>;
|
||||||
|
type ZkPrng = ChaCha20Rng;
|
||||||
|
|
||||||
|
fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs {
|
||||||
|
let last_step = trace.length() - 1;
|
||||||
|
// Note that the message is not part of the execution trace but is part of the public
|
||||||
|
// inputs. This is explained in the reference description of the DSA and intuitively
|
||||||
|
// it is done in order to make sure that the message is part of the Fiat-Shamir
|
||||||
|
// transcript and hence binds the proof/signature to the message
|
||||||
|
PublicInputs {
|
||||||
|
pub_key: [
|
||||||
|
trace.get(4, last_step),
|
||||||
|
trace.get(5, last_step),
|
||||||
|
trace.get(6, last_step),
|
||||||
|
trace.get(7, last_step),
|
||||||
|
],
|
||||||
|
msg: self.message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn options(&self) -> &ProofOptions {
|
||||||
|
&self.options
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_trace_lde<E: FieldElement<BaseField = Self::BaseField>>(
|
||||||
|
&self,
|
||||||
|
trace_info: &TraceInfo,
|
||||||
|
main_trace: &ColMatrix<Self::BaseField>,
|
||||||
|
domain: &StarkDomain<Self::BaseField>,
|
||||||
|
partition_option: PartitionOptions,
|
||||||
|
zk_parameters: Option<ZkParameters>,
|
||||||
|
prng: &mut Option<Self::ZkPrng>,
|
||||||
|
) -> (Self::TraceLde<E>, TracePolyTable<E>) {
|
||||||
|
DefaultTraceLde::new(trace_info, main_trace, domain, partition_option, zk_parameters, prng)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_evaluator<'a, E: FieldElement<BaseField = Self::BaseField>>(
|
||||||
|
&self,
|
||||||
|
air: &'a Self::Air,
|
||||||
|
aux_rand_elements: Option<AuxRandElements<E>>,
|
||||||
|
composition_coefficients: ConstraintCompositionCoefficients<E>,
|
||||||
|
) -> Self::ConstraintEvaluator<'a, E> {
|
||||||
|
DefaultConstraintEvaluator::new(air, aux_rand_elements, composition_coefficients)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_constraint_commitment<E: FieldElement<BaseField = Self::BaseField>>(
|
||||||
|
&self,
|
||||||
|
composition_poly_trace: CompositionPolyTrace<E>,
|
||||||
|
num_constraint_composition_columns: usize,
|
||||||
|
domain: &StarkDomain<Self::BaseField>,
|
||||||
|
partition_options: PartitionOptions,
|
||||||
|
zk_parameters: Option<ZkParameters>,
|
||||||
|
prng: &mut Option<Self::ZkPrng>,
|
||||||
|
) -> (Self::ConstraintCommitment<E>, CompositionPoly<E>) {
|
||||||
|
DefaultConstraintCommitment::new(
|
||||||
|
composition_poly_trace,
|
||||||
|
num_constraint_composition_columns,
|
||||||
|
domain,
|
||||||
|
partition_options,
|
||||||
|
zk_parameters,
|
||||||
|
prng,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use super::{CubeExtension, Felt, FieldElement, StarkField, ZERO};
|
|||||||
pub mod blake;
|
pub mod blake;
|
||||||
|
|
||||||
mod rescue;
|
mod rescue;
|
||||||
|
pub(crate) use rescue::{ARK1, ARK2, DIGEST_SIZE, MDS, STATE_WIDTH};
|
||||||
pub mod rpo {
|
pub mod rpo {
|
||||||
pub use super::rescue::{Rpo256, RpoDigest, RpoDigestError};
|
pub use super::rescue::{Rpo256, RpoDigest, RpoDigestError};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ mod arch;
|
|||||||
pub use arch::optimized::{add_constants_and_apply_inv_sbox, add_constants_and_apply_sbox};
|
pub use arch::optimized::{add_constants_and_apply_inv_sbox, add_constants_and_apply_sbox};
|
||||||
|
|
||||||
mod mds;
|
mod mds;
|
||||||
use mds::{apply_mds, MDS};
|
pub(crate) use mds::{apply_mds, MDS};
|
||||||
|
|
||||||
mod rpo;
|
mod rpo;
|
||||||
pub use rpo::{Rpo256, RpoDigest, RpoDigestError};
|
pub use rpo::{Rpo256, RpoDigest, RpoDigestError};
|
||||||
@@ -26,7 +26,7 @@ const NUM_ROUNDS: usize = 7;
|
|||||||
|
|
||||||
/// Sponge state is set to 12 field elements or 96 bytes; 8 elements are reserved for rate and
|
/// Sponge state is set to 12 field elements or 96 bytes; 8 elements are reserved for rate and
|
||||||
/// the remaining 4 elements are reserved for capacity.
|
/// the remaining 4 elements are reserved for capacity.
|
||||||
const STATE_WIDTH: usize = 12;
|
pub(crate) const STATE_WIDTH: usize = 12;
|
||||||
|
|
||||||
/// The rate portion of the state is located in elements 4 through 11.
|
/// The rate portion of the state is located in elements 4 through 11.
|
||||||
const RATE_RANGE: Range<usize> = 4..12;
|
const RATE_RANGE: Range<usize> = 4..12;
|
||||||
@@ -42,8 +42,8 @@ const CAPACITY_RANGE: Range<usize> = 0..4;
|
|||||||
///
|
///
|
||||||
/// The digest is returned from state elements 4, 5, 6, and 7 (the first four elements of the
|
/// The digest is returned from state elements 4, 5, 6, and 7 (the first four elements of the
|
||||||
/// rate portion).
|
/// rate portion).
|
||||||
const DIGEST_RANGE: Range<usize> = 4..8;
|
pub(crate) const DIGEST_RANGE: Range<usize> = 4..8;
|
||||||
const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start;
|
pub(crate) const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start;
|
||||||
|
|
||||||
/// The number of bytes needed to encoded a digest
|
/// The number of bytes needed to encoded a digest
|
||||||
const DIGEST_BYTES: usize = 32;
|
const DIGEST_BYTES: usize = 32;
|
||||||
@@ -144,7 +144,7 @@ fn add_constants(state: &mut [Felt; STATE_WIDTH], ark: &[Felt; STATE_WIDTH]) {
|
|||||||
///
|
///
|
||||||
/// The constants are broken up into two arrays ARK1 and ARK2; ARK1 contains the constants for the
|
/// The constants are broken up into two arrays ARK1 and ARK2; ARK1 contains the constants for the
|
||||||
/// first half of RPO round, and ARK2 contains constants for the second half of RPO round.
|
/// first half of RPO round, and ARK2 contains constants for the second half of RPO round.
|
||||||
const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [
|
pub(crate) const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [
|
||||||
[
|
[
|
||||||
Felt::new(5789762306288267392),
|
Felt::new(5789762306288267392),
|
||||||
Felt::new(6522564764413701783),
|
Felt::new(6522564764413701783),
|
||||||
@@ -245,7 +245,7 @@ const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [
|
pub(crate) const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = [
|
||||||
[
|
[
|
||||||
Felt::new(6077062762357204287),
|
Felt::new(6077062762357204287),
|
||||||
Felt::new(15277620170502011191),
|
Felt::new(15277620170502011191),
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
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, slice};
|
||||||
|
|
||||||
|
use rand::{
|
||||||
|
distributions::{Standard, Uniform},
|
||||||
|
prelude::Distribution,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO};
|
use super::{Digest, Felt, StarkField, DIGEST_BYTES, DIGEST_SIZE, ZERO};
|
||||||
@@ -126,6 +130,18 @@ impl Randomizable for RpoDigest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Distribution<RpoDigest> for Standard {
|
||||||
|
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> RpoDigest {
|
||||||
|
let mut res = [ZERO; DIGEST_SIZE];
|
||||||
|
let uni_dist = Uniform::from(0..Felt::MODULUS);
|
||||||
|
for r in res.iter_mut() {
|
||||||
|
let sampled_integer = uni_dist.sample(rng);
|
||||||
|
*r = Felt::new(sampled_integer);
|
||||||
|
}
|
||||||
|
RpoDigest::new(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CONVERSIONS: FROM RPO DIGEST
|
// CONVERSIONS: FROM RPO DIGEST
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -174,6 +174,36 @@ impl RandomCoin for RpoRandomCoin {
|
|||||||
|
|
||||||
Ok(values)
|
Ok(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reseed_with_salt(
|
||||||
|
&mut self,
|
||||||
|
data: <Self::Hasher as winter_crypto::Hasher>::Digest,
|
||||||
|
salt: Option<<Self::Hasher as winter_crypto::Hasher>::Digest>,
|
||||||
|
) {
|
||||||
|
// Reset buffer
|
||||||
|
self.current = RATE_START;
|
||||||
|
|
||||||
|
// Add the new seed material to the first half of the rate portion of the RPO state
|
||||||
|
let data: Word = data.into();
|
||||||
|
|
||||||
|
self.state[RATE_START] += data[0];
|
||||||
|
self.state[RATE_START + 1] += data[1];
|
||||||
|
self.state[RATE_START + 2] += data[2];
|
||||||
|
self.state[RATE_START + 3] += data[3];
|
||||||
|
|
||||||
|
if let Some(salt) = salt {
|
||||||
|
// Add the salt to the second half of the rate portion of the RPO state
|
||||||
|
let data: Word = salt.into();
|
||||||
|
|
||||||
|
self.state[RATE_START + 4] += data[0];
|
||||||
|
self.state[RATE_START + 5] += data[1];
|
||||||
|
self.state[RATE_START + 6] += data[2];
|
||||||
|
self.state[RATE_START + 7] += data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absorb
|
||||||
|
Rpo256::apply_permutation(&mut self.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FELT RNG IMPLEMENTATION
|
// FELT RNG IMPLEMENTATION
|
||||||
|
|||||||
@@ -172,6 +172,36 @@ impl RandomCoin for RpxRandomCoin {
|
|||||||
|
|
||||||
Ok(values)
|
Ok(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reseed_with_salt(
|
||||||
|
&mut self,
|
||||||
|
data: <Self::Hasher as winter_crypto::Hasher>::Digest,
|
||||||
|
salt: Option<<Self::Hasher as winter_crypto::Hasher>::Digest>,
|
||||||
|
) {
|
||||||
|
// Reset buffer
|
||||||
|
self.current = RATE_START;
|
||||||
|
|
||||||
|
// Add the new seed material to the first half of the rate portion of the RPO state
|
||||||
|
let data: Word = data.into();
|
||||||
|
|
||||||
|
self.state[RATE_START] += data[0];
|
||||||
|
self.state[RATE_START + 1] += data[1];
|
||||||
|
self.state[RATE_START + 2] += data[2];
|
||||||
|
self.state[RATE_START + 3] += data[3];
|
||||||
|
|
||||||
|
if let Some(salt) = salt {
|
||||||
|
// Add the salt to the second half of the rate portion of the RPO state
|
||||||
|
let data: Word = salt.into();
|
||||||
|
|
||||||
|
self.state[RATE_START + 4] += data[0];
|
||||||
|
self.state[RATE_START + 5] += data[1];
|
||||||
|
self.state[RATE_START + 6] += data[2];
|
||||||
|
self.state[RATE_START + 7] += data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absorb
|
||||||
|
Rpx256::apply_permutation(&mut self.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FELT RNG IMPLEMENTATION
|
// FELT RNG IMPLEMENTATION
|
||||||
|
|||||||
Reference in New Issue
Block a user