From f5e69432b83f48eb5205afb1f55a9c51583c6d3f Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Mon, 18 May 2026 14:55:18 +0800 Subject: [PATCH 01/19] chore(openvm): v1.6.0 --- .github/CODEOWNERS | 10 - Cargo.lock | 1380 ++++------------- Cargo.toml | 60 +- crates/build-guest/src/main.rs | 14 +- crates/build-guest/src/verifier.rs | 2 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- crates/circuits/batch-circuit/openvm.toml | 3 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- crates/circuits/bundle-circuit/openvm.toml | 3 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/circuits/chunk-circuit/openvm.toml | 3 +- crates/integration/Cargo.toml | 1 - crates/integration/src/axiom.rs | 165 -- crates/integration/src/lib.rs | 24 - crates/prover/src/setup.rs | 5 +- .../batch/src/blob_consistency/openvm.rs | 13 +- .../types/batch/src/blob_consistency/types.rs | 12 +- crates/types/batch/src/witness.rs | 2 +- crates/types/chunk/src/crypto/bn254.rs | 9 +- 22 files changed, 383 insertions(+), 1335 deletions(-) delete mode 100644 .github/CODEOWNERS delete mode 100644 crates/integration/src/axiom.rs diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index e8762938..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,10 +0,0 @@ -* @roynalnaruto @lispc -crates/integration/ @noel2004 -crates/prover/ @roynalnaruto -crates/verifier/ @roynalnaruto @noel2004 -crates/circuits/types/ @roynalnaruto @noel2004 -crates/circuits/chunk-circuit/ @lispc @lightsing -crates/circuits/batch-circuit/ @roynalnaruto @noel2004 -crates/circuits/bundle-circuit/ @roynalnaruto @noel2004 -crates/build-guest/ @lispc -.github/ @roynalnaruto diff --git a/Cargo.lock b/Cargo.lock index d21f72fb..4e60a044 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,17 +50,6 @@ dependencies = [ "core_extensions", ] -[[package]] -name = "addchain" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" -dependencies = [ - "num-bigint 0.3.3", - "num-integer", - "num-traits", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -879,7 +868,7 @@ dependencies = [ "fnv", "hashbrown 0.15.5", "itertools 0.13.0", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "zeroize", @@ -896,7 +885,7 @@ dependencies = [ "ark-serialize 0.3.0", "ark-std 0.3.0", "derivative", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "paste", "rustc_version 0.3.3", @@ -916,7 +905,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "paste", "rustc_version 0.4.1", @@ -937,7 +926,7 @@ dependencies = [ "digest 0.10.7", "educe", "itertools 0.13.0", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "paste", "zeroize", @@ -979,7 +968,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-traits", "quote", "syn 1.0.109", @@ -991,7 +980,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-traits", "proc-macro2", "quote", @@ -1004,7 +993,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-traits", "proc-macro2", "quote", @@ -1037,7 +1026,7 @@ dependencies = [ "ark-relations", "ark-std 0.5.0", "educe", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "tracing", @@ -1073,7 +1062,7 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-std 0.4.0", "digest 0.10.7", - "num-bigint 0.4.6", + "num-bigint", ] [[package]] @@ -1086,7 +1075,7 @@ dependencies = [ "ark-std 0.5.0", "arrayvec", "digest 0.10.7", - "num-bigint 0.4.6", + "num-bigint", ] [[package]] @@ -1224,30 +1213,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "axiom-sdk" -version = "1.0.10" -source = "git+https://github.com/axiom-crypto/axiom-api-cli.git?tag=v1.0.10#d1275f0f7df50a098e274092b39c122a23c4b9da" -dependencies = [ - "bytes", - "cargo_metadata 0.21.0", - "chrono", - "dirs", - "eyre", - "flate2", - "hex", - "openvm-build", - "reqwest", - "rustc_version 0.4.1", - "scopeguard", - "serde", - "serde_json", - "tar", - "toml_edit 0.23.7", - "url", - "walkdir", -] - [[package]] name = "az" version = "1.2.1" @@ -1621,15 +1586,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-platform" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" -dependencies = [ - "serde", -] - [[package]] name = "cargo-platform" version = "0.3.1" @@ -1639,22 +1595,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-util-schemas" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc1a6f7b5651af85774ae5a34b4e8be397d9cf4bc063b7e6dbd99a841837830" -dependencies = [ - "semver 1.0.27", - "serde", - "serde-untagged", - "serde-value", - "thiserror 2.0.17", - "toml", - "unicode-xid", - "url", -] - [[package]] name = "cargo_metadata" version = "0.18.1" @@ -1669,21 +1609,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "cargo_metadata" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfca2aaa699835ba88faf58a06342a314a950d2b9686165e038286c30316868" -dependencies = [ - "camino", - "cargo-platform 0.2.0", - "cargo-util-schemas", - "semver 1.0.27", - "serde", - "serde_json", - "thiserror 2.0.17", -] - [[package]] name = "cargo_metadata" version = "0.23.1" @@ -1787,33 +1712,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" -[[package]] -name = "color-eyre" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "colorchoice" version = "1.0.4" @@ -1830,19 +1728,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "console" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" -dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "unicode-width", - "windows-sys 0.61.2", -] - [[package]] name = "const-hex" version = "1.17.0" @@ -1960,15 +1845,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - [[package]] name = "critical-section" version = "1.2.0" @@ -2031,33 +1907,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crossterm" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" -dependencies = [ - "bitflags", - "crossterm_winapi", - "derive_more 2.0.1", - "document-features", - "mio", - "parking_lot", - "rustix", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - [[package]] name = "crunchy" version = "0.2.4" @@ -2380,27 +2229,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.2", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -2412,15 +2240,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "dotenvy" version = "0.15.7" @@ -2535,12 +2354,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encode_unicode" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" - [[package]] name = "encoder-standard" version = "0.1.0" @@ -2549,15 +2362,6 @@ dependencies = [ "zstd", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "endian-type" version = "0.1.2" @@ -2613,17 +2417,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "erased-serde" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" -dependencies = [ - "serde", - "serde_core", - "typeid", -] - [[package]] name = "errno" version = "0.3.14" @@ -2753,39 +2546,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "bitvec", - "byteorder", - "ff_derive", "rand_core 0.6.4", "subtle", ] -[[package]] -name = "ff_derive" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f10d12652036b0e99197587c6ba87a8fc3031986499973c030d8b44fcc151b60" -dependencies = [ - "addchain", - "num-bigint 0.3.3", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "filetime" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.60.2", -] - [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -2804,16 +2568,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "flate2" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2963,21 +2717,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" -[[package]] -name = "fuzzy-matcher" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" -dependencies = [ - "thread_local", -] - -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - [[package]] name = "generational-arena" version = "0.2.9" @@ -3138,25 +2877,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "h2" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.12.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "halo2" version = "0.1.0-beta.2" @@ -3198,7 +2918,7 @@ dependencies = [ "halo2-axiom", "itertools 0.11.0", "log", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "poseidon-primitives", @@ -3217,7 +2937,7 @@ checksum = "645c00681fdd1febaf552d8814e9f5a6a142d81a1514102190da07039588b366" dependencies = [ "halo2-base", "itertools 0.11.0", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "rand 0.8.5", @@ -3243,35 +2963,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "halo2curves" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b756596082144af6e57105a20403b7b80fe9dccd085700b74fae3af523b74dba" -dependencies = [ - "blake2", - "digest 0.10.7", - "ff 0.13.1", - "group 0.13.0", - "halo2derive", - "hex", - "lazy_static", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "pairing 0.23.0", - "paste", - "rand 0.8.5", - "rand_core 0.6.4", - "rayon", - "serde", - "serde_arrays", - "sha2 0.10.9", - "static_assertions", - "subtle", - "unroll", -] - [[package]] name = "halo2curves-axiom" version = "0.7.2" @@ -3284,7 +2975,7 @@ dependencies = [ "group 0.13.0", "hex", "lazy_static", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "pairing 0.23.0", "pasta_curves 0.5.1", @@ -3311,7 +3002,7 @@ dependencies = [ "group 0.13.0", "hex", "lazy_static", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "pairing 0.23.0", "pasta_curves 0.5.1", @@ -3327,20 +3018,6 @@ dependencies = [ "unroll", ] -[[package]] -name = "halo2derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb99e7492b4f5ff469d238db464131b86c2eaac814a78715acba369f64d2c76" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -3496,7 +3173,6 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2", "http", "http-body", "httparse", @@ -3508,22 +3184,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -3559,11 +3219,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", - "system-configuration", "tokio", "tower-service", "tracing", - "windows-registry", ] [[package]] @@ -3756,20 +3414,6 @@ dependencies = [ "hybrid-array", ] -[[package]] -name = "inquire" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2628910d0114e9139056161d8644a2026be7b117f8498943f9437748b04c9e0a" -dependencies = [ - "bitflags", - "crossterm", - "dyn-clone", - "fuzzy-matcher", - "unicode-segmentation", - "unicode-width", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -3835,51 +3479,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] -name = "jiff" -version = "0.2.16" +name = "jobserver" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" -dependencies = [ - "jiff-static", - "jiff-tzdb-platform", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", - "windows-sys 0.61.2", -] - -[[package]] -name = "jiff-static" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "jiff-tzdb" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" - -[[package]] -name = "jiff-tzdb-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" -dependencies = [ - "jiff-tzdb", -] - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.4", "libc", @@ -3927,13 +3530,13 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "ecdsa", "elliptic-curve", "ff 0.13.1", "hex-literal", - "num-bigint 0.4.6", + "num-bigint", "once_cell", "openvm", "openvm-algebra-guest", @@ -3968,7 +3571,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -3993,17 +3596,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" -[[package]] -name = "libredox" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags", - "libc", - "redox_syscall", -] - [[package]] name = "libsecp256k1" version = "0.7.2" @@ -4062,12 +3654,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "lock_api" version = "0.4.14" @@ -4198,28 +3784,12 @@ dependencies = [ "indexmap 2.12.0", "metrics", "num_cpus", - "ordered-float 4.6.0", + "ordered-float", "quanta", "radix_trie", "sketches-ddsketch", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -4227,7 +3797,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "simd-adler32", ] [[package]] @@ -4237,7 +3806,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.61.2", ] @@ -4325,7 +3893,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -4333,17 +3901,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -4397,7 +3954,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", ] @@ -4411,7 +3968,7 @@ dependencies = [ "bitvec", "either", "lru 0.12.5", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-modular", "num-traits", @@ -4424,7 +3981,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", ] @@ -4471,18 +4028,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "nums" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3c74f925fb8cfc49a8022f2afce48a0683b70f9e439885594e84c5edbf5b01" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "rand 0.8.5", -] - [[package]] name = "nybbles" version = "0.3.4" @@ -4676,13 +4221,13 @@ dependencies = [ [[package]] name = "openvm" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "bytemuck", "getrandom 0.2.16", "getrandom 0.3.4", - "num-bigint 0.4.6", + "num-bigint", "openvm-custom-insn", "openvm-platform", "openvm-rv32im-guest", @@ -4691,8 +4236,8 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "blstrs", "cfg-if", @@ -4700,7 +4245,7 @@ dependencies = [ "derive_more 1.0.0", "eyre", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm-algebra-transpiler", "openvm-circuit", @@ -4716,7 +4261,7 @@ dependencies = [ "openvm-rv32im-circuit", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", "serde", "serde_with", "strum 0.26.3", @@ -4724,8 +4269,8 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-macros-common", "quote", @@ -4734,11 +4279,11 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "num-bigint 0.4.6", + "num-bigint", "once_cell", "openvm-algebra-complex-macros", "openvm-algebra-moduli-macros", @@ -4750,10 +4295,10 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", "num-prime", "openvm-macros-common", "quote", @@ -4762,8 +4307,8 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-algebra-guest", "openvm-instructions", @@ -4776,8 +4321,8 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "clap", "derive_more 1.0.0", @@ -4794,7 +4339,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "openvm-transpiler", - "rand 0.8.5", + "rand 0.9.2", "rand_chacha 0.3.1", "tiny-keccak", "tokio", @@ -4803,8 +4348,8 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4818,8 +4363,8 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4838,14 +4383,14 @@ dependencies = [ "openvm-rv32im-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", "serde", ] [[package]] name = "openvm-bigint-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4853,8 +4398,8 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-bigint-guest", "openvm-instructions", @@ -4868,8 +4413,8 @@ dependencies = [ [[package]] name = "openvm-build" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4880,8 +4425,8 @@ dependencies = [ [[package]] name = "openvm-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "abi_stable", "backtrace", @@ -4909,7 +4454,7 @@ dependencies = [ "openvm-stark-sdk", "p3-baby-bear", "p3-field", - "rand 0.8.5", + "rand 0.9.2", "rustc-hash 2.1.1", "serde", "serde-big-array", @@ -4920,8 +4465,8 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4931,26 +4476,26 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm-circuit-primitives-derive", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", "openvm-stark-backend", - "rand 0.8.5", + "rand 0.9.2", "tracing", ] [[package]] name = "openvm-circuit-primitives-derive" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "itertools 0.14.0", "quote", @@ -4959,8 +4504,8 @@ dependencies = [ [[package]] name = "openvm-continuations" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "derivative", "openvm-circuit", @@ -4968,14 +4513,15 @@ dependencies = [ "openvm-native-recursion", "openvm-stark-backend", "openvm-stark-sdk", + "p3-bn254", "serde", "static_assertions", ] [[package]] name = "openvm-cuda-backend" -version = "1.2.3" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.2.3#abd3c8508bac5409deca284928fc37219448403a" +version = "1.4.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" dependencies = [ "bincode 2.0.1", "bincode_derive", @@ -5006,8 +4552,8 @@ dependencies = [ [[package]] name = "openvm-cuda-builder" -version = "1.2.3" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.2.3#abd3c8508bac5409deca284928fc37219448403a" +version = "1.4.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" dependencies = [ "cc", "glob", @@ -5015,8 +4561,8 @@ dependencies = [ [[package]] name = "openvm-cuda-common" -version = "1.2.3" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.2.3#abd3c8508bac5409deca284928fc37219448403a" +version = "1.4.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" dependencies = [ "bytesize", "ctor", @@ -5030,7 +4576,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "proc-macro2", "quote", @@ -5039,8 +4585,8 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "blstrs", "cfg-if", @@ -5049,7 +4595,7 @@ dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "hex-literal", "lazy_static", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "once_cell", "openvm-algebra-circuit", @@ -5064,7 +4610,7 @@ dependencies = [ "openvm-rv32-adapters", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", "serde", "serde_with", "strum 0.26.3", @@ -5072,8 +4618,8 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "ecdsa", "elliptic-curve", @@ -5091,8 +4637,8 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-macros-common", "quote", @@ -5101,8 +4647,8 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-ecc-guest", "openvm-instructions", @@ -5115,13 +4661,13 @@ dependencies = [ [[package]] name = "openvm-instructions" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "backtrace", "derive-new 0.6.0", "itertools 0.14.0", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm-instructions-derive", "openvm-stark-backend", @@ -5132,8 +4678,8 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "quote", "syn 2.0.110", @@ -5141,8 +4687,8 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5161,7 +4707,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "p3-keccak-air", - "rand 0.8.5", + "rand 0.9.2", "serde", "strum 0.26.3", "tiny-keccak", @@ -5169,16 +4715,16 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-platform", ] [[package]] name = "openvm-keccak256-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5191,20 +4737,20 @@ dependencies = [ [[package]] name = "openvm-macros-common" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "syn 2.0.110", ] [[package]] name = "openvm-mod-circuit-builder" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cuda-runtime-sys", "itertools 0.14.0", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm-circuit", "openvm-circuit-primitives", @@ -5215,13 +4761,14 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "rand 0.8.5", + "rand 0.9.2", "tracing", ] [[package]] name = "openvm-native-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5243,7 +4790,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "p3-field", - "rand 0.8.5", + "rand 0.9.2", "serde", "static_assertions", "strum 0.26.3", @@ -5251,12 +4798,12 @@ dependencies = [ [[package]] name = "openvm-native-compiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "backtrace", "itertools 0.14.0", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "openvm-circuit", "openvm-instructions", @@ -5274,8 +4821,8 @@ dependencies = [ [[package]] name = "openvm-native-compiler-derive" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "quote", "syn 2.0.110", @@ -5283,8 +4830,8 @@ dependencies = [ [[package]] name = "openvm-native-recursion" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "itertools 0.14.0", @@ -5301,6 +4848,7 @@ dependencies = [ "p3-merkle-tree", "p3-symmetric", "rand 0.8.5", + "rand 0.9.2", "serde", "serde_json", "serde_with", @@ -5310,8 +4858,8 @@ dependencies = [ [[package]] name = "openvm-native-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-instructions", "openvm-transpiler", @@ -5320,14 +4868,14 @@ dependencies = [ [[package]] name = "openvm-pairing" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "hex-literal", "itertools 0.14.0", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm", "openvm-algebra-complex-macros", @@ -5339,21 +4887,20 @@ dependencies = [ "openvm-pairing-guest", "openvm-platform", "openvm-rv32im-guest", - "rand 0.8.5", "serde", ] [[package]] name = "openvm-pairing-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm-algebra-circuit", "openvm-circuit", @@ -5369,37 +4916,36 @@ dependencies = [ "openvm-rv32im-circuit", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", "serde", "strum 0.26.3", ] [[package]] name = "openvm-pairing-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "hex-literal", "itertools 0.14.0", "lazy_static", - "num-bigint 0.4.6", + "num-bigint", "num-traits", "openvm", "openvm-algebra-guest", "openvm-algebra-moduli-macros", "openvm-custom-insn", "openvm-ecc-guest", - "rand 0.8.5", "serde", "strum_macros 0.26.4", ] [[package]] name = "openvm-pairing-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-instructions", "openvm-pairing-guest", @@ -5411,8 +4957,8 @@ dependencies = [ [[package]] name = "openvm-platform" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "libm", "openvm-custom-insn", @@ -5421,26 +4967,25 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "derivative", "lazy_static", "openvm-cuda-builder", "openvm-stark-backend", "openvm-stark-sdk", - "p3-monty-31", "p3-poseidon2", "p3-poseidon2-air", "p3-symmetric", - "rand 0.8.5", + "rand 0.9.2", "zkhash", ] [[package]] name = "openvm-rv32-adapters" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5451,19 +4996,19 @@ dependencies = [ "openvm-rv32im-circuit", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", ] [[package]] name = "openvm-rv32im-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "openvm-circuit", "openvm-circuit-derive", @@ -5476,15 +5021,15 @@ dependencies = [ "openvm-rv32im-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", "serde", "strum 0.26.3", ] [[package]] name = "openvm-rv32im-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-custom-insn", "p3-field", @@ -5493,8 +5038,8 @@ dependencies = [ [[package]] name = "openvm-rv32im-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5509,8 +5054,8 @@ dependencies = [ [[package]] name = "openvm-sdk" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "bitcode", "bon", @@ -5523,7 +5068,7 @@ dependencies = [ "hex", "itertools 0.14.0", "metrics", - "num-bigint 0.4.6", + "num-bigint", "openvm", "openvm-algebra-circuit", "openvm-algebra-transpiler", @@ -5550,8 +5095,9 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "openvm-transpiler", + "p3-bn254", "p3-fri", - "rand 0.8.5", + "rand 0.9.2", "rrs-lib", "serde", "serde_json", @@ -5566,8 +5112,8 @@ dependencies = [ [[package]] name = "openvm-sha2" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-sha256-guest", "sha2 0.10.9", @@ -5575,19 +5121,19 @@ dependencies = [ [[package]] name = "openvm-sha256-air" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-circuit-primitives", "openvm-stark-backend", - "rand 0.8.5", + "rand 0.9.2", "sha2 0.10.9", ] [[package]] name = "openvm-sha256-circuit" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5604,7 +5150,7 @@ dependencies = [ "openvm-sha256-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", + "rand 0.9.2", "serde", "sha2 0.10.9", "strum 0.26.3", @@ -5612,16 +5158,16 @@ dependencies = [ [[package]] name = "openvm-sha256-guest" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-platform", ] [[package]] name = "openvm-sha256-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5634,8 +5180,8 @@ dependencies = [ [[package]] name = "openvm-stark-backend" -version = "1.2.3" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.2.3#abd3c8508bac5409deca284928fc37219448403a" +version = "1.4.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" dependencies = [ "bitcode", "cfg-if", @@ -5650,7 +5196,6 @@ dependencies = [ "p3-field", "p3-matrix", "p3-maybe-rayon", - "p3-uni-stark", "p3-util", "rayon", "rustc-hash 2.1.1", @@ -5662,8 +5207,8 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" -version = "1.2.3" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.2.3#abd3c8508bac5409deca284928fc37219448403a" +version = "1.4.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" dependencies = [ "dashmap", "derivative", @@ -5673,10 +5218,11 @@ dependencies = [ "metrics", "metrics-tracing-context", "metrics-util", + "num-bigint", "openvm-stark-backend", "p3-baby-bear", "p3-blake3", - "p3-bn254-fr", + "p3-bn254", "p3-dft", "p3-fri", "p3-goldilocks", @@ -5686,7 +5232,7 @@ dependencies = [ "p3-poseidon", "p3-poseidon2", "p3-symmetric", - "rand 0.8.5", + "rand 0.9.2", "serde", "serde_json", "static_assertions", @@ -5699,8 +5245,8 @@ dependencies = [ [[package]] name = "openvm-transpiler" -version = "1.4.3" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +version = "1.6.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "elf", "eyre", @@ -5712,21 +5258,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - [[package]] name = "ordered-float" version = "4.6.0" @@ -5736,12 +5267,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "owo-colors" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" - [[package]] name = "p256" version = "0.13.2" @@ -5757,13 +5282,13 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.4.3#e8feb93717200e6f334b4f368dd2d0a143f69436" +source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" dependencies = [ "ecdsa", "elliptic-curve", "ff 0.13.1", "hex-literal", - "num-bigint 0.4.6", + "num-bigint", "openvm", "openvm-algebra-guest", "openvm-algebra-moduli-macros", @@ -5774,8 +5299,9 @@ dependencies = [ [[package]] name = "p3-air" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daee3082e2ca0db2ac876c43c9c8fd53204b0fcb95cfe7258d21f4a925ad82c4" dependencies = [ "p3-field", "p3-matrix", @@ -5783,22 +5309,24 @@ dependencies = [ [[package]] name = "p3-baby-bear" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1a49f4d9c8b8cbdab61e25d9de1b78b3c8347dd2fb88b11d990b3efa8cdd3a" dependencies = [ + "p3-challenger", "p3-field", "p3-mds", "p3-monty-31", "p3-poseidon2", "p3-symmetric", - "rand 0.8.5", - "serde", + "rand 0.9.2", ] [[package]] name = "p3-blake3" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f97fd783752532861bf29bac344b7c226a0d1e2151148834c43c651a5d401" dependencies = [ "blake3", "p3-symmetric", @@ -5806,27 +5334,30 @@ dependencies = [ ] [[package]] -name = "p3-bn254-fr" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +name = "p3-bn254" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923bd91df7dd93481b4bfb53aa903d46d1a49d51160513472a5e95ca92ef1b46" dependencies = [ - "ff 0.13.1", - "halo2curves", - "num-bigint 0.4.6", + "num-bigint", "p3-field", "p3-poseidon2", "p3-symmetric", - "rand 0.8.5", + "p3-util", + "paste", + "rand 0.9.2", "serde", ] [[package]] name = "p3-challenger" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d2d45f5a51dc3f965e8d6da60a6c26c807e88657863d56da275eaa05ad36f1" dependencies = [ "p3-field", "p3-maybe-rayon", + "p3-monty-31", "p3-symmetric", "p3-util", "tracing", @@ -5834,8 +5365,9 @@ dependencies = [ [[package]] name = "p3-commit" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6d7dcb58a8f21f0e1325dc7f7699ad749878ccbe7e286e61f9d46bde2bfa88" dependencies = [ "itertools 0.14.0", "p3-challenger", @@ -5848,38 +5380,40 @@ dependencies = [ [[package]] name = "p3-dft" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beabb40bc8ac7f5f95870f271fb844c7e2e1ebb7f0761a8eebb2614b56c6b1c1" dependencies = [ "itertools 0.14.0", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", + "spin 0.10.0", "tracing", ] [[package]] name = "p3-field" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4819a3e4c1882431a63d4847ffa10d110017aee4cb9cf4319ca6dca191930969" dependencies = [ "itertools 0.14.0", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "nums", + "num-bigint", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "paste", + "rand 0.9.2", "serde", "tracing", ] [[package]] name = "p3-fri" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13ca6a795cfc4180425fbf16dfdb4c9c2bfa85971dd55b5930d97b513e0835df" dependencies = [ "itertools 0.14.0", "p3-challenger", @@ -5890,32 +5424,36 @@ dependencies = [ "p3-matrix", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "rand 0.9.2", "serde", + "thiserror 2.0.17", "tracing", ] [[package]] name = "p3-goldilocks" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c47d5c650bbeb25941b9a1fa9bfaf59b3cd202a438ea2c20892489af001399" dependencies = [ - "num-bigint 0.4.6", + "num-bigint", + "p3-challenger", "p3-dft", "p3-field", "p3-mds", - "p3-poseidon", "p3-poseidon2", "p3-symmetric", "p3-util", - "rand 0.8.5", + "paste", + "rand 0.9.2", "serde", ] [[package]] name = "p3-interpolation" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27a3696641a8f4ec990ff8c91862fb4f3b4ff29f589f78005d046023fe3550f" dependencies = [ "p3-field", "p3-matrix", @@ -5925,10 +5463,10 @@ dependencies = [ [[package]] name = "p3-keccak" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61b090fb42152d1fcb2f82227b8619b1b022f9cd4a123123dccc9c2ab75d5de" dependencies = [ - "itertools 0.14.0", "p3-field", "p3-symmetric", "p3-util", @@ -5937,73 +5475,75 @@ dependencies = [ [[package]] name = "p3-keccak-air" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4832d817455f7a4a35b598cbb8a42f1ee0430ee82df0203956c26917b2509865" dependencies = [ "p3-air", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "rand 0.9.2", "tracing", ] [[package]] name = "p3-koala-bear" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb02789fca0950e246123d652bd78e75a76e3b90a651fd88dbb215cd3e81f5a" dependencies = [ + "p3-challenger", "p3-field", - "p3-mds", "p3-monty-31", "p3-poseidon2", "p3-symmetric", - "rand 0.8.5", - "serde", + "rand 0.9.2", ] [[package]] name = "p3-matrix" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6fde449bd2963d394284ec46db8c647e6a5602d90601117b76752072ab54168" dependencies = [ "itertools 0.14.0", "p3-field", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "rand 0.9.2", "serde", "tracing", - "transpose", ] [[package]] name = "p3-maybe-rayon" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54afab3883d8a14676b492709d6c4e9fa535c36718b737db0817aacfaaaa11f6" dependencies = [ "rayon", ] [[package]] name = "p3-mds" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3895055d735ac96d010747b3aaabd4c2645b9fd80226960550318db2e25afb75" dependencies = [ - "itertools 0.14.0", "p3-dft", "p3-field", - "p3-matrix", "p3-symmetric", "p3-util", - "rand 0.8.5", + "rand 0.9.2", ] [[package]] name = "p3-merkle-tree" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e20f61ea816e94f83ed7b8134a5e98d0cad7bd6dff226bc1da17a5143c63cb" dependencies = [ "itertools 0.14.0", "p3-commit", @@ -6012,18 +5552,20 @@ dependencies = [ "p3-maybe-rayon", "p3-symmetric", "p3-util", - "rand 0.8.5", + "rand 0.9.2", "serde", + "thiserror 2.0.17", "tracing", ] [[package]] name = "p3-monty-31" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fe0be661891af1f703ceaf57334fcbd540804988984dc2b500dd99740e7c81" dependencies = [ "itertools 0.14.0", - "num-bigint 0.4.6", + "num-bigint", "p3-dft", "p3-field", "p3-matrix", @@ -6032,85 +5574,72 @@ dependencies = [ "p3-poseidon2", "p3-symmetric", "p3-util", - "rand 0.8.5", + "paste", + "rand 0.9.2", "serde", + "spin 0.10.0", "tracing", - "transpose", ] [[package]] name = "p3-poseidon" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548af7ff569975882bc411f653aba7d89a6d85813ca58ef922fd0b1ecb6b5866" dependencies = [ "p3-field", "p3-mds", "p3-symmetric", - "rand 0.8.5", + "rand 0.9.2", ] [[package]] name = "p3-poseidon2" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6fc2368447576283f8b3849a36095017f25addf06eab9e33b0ce7f96b0b99d" dependencies = [ - "gcd", "p3-field", "p3-mds", "p3-symmetric", - "rand 0.8.5", + "p3-util", + "rand 0.9.2", ] [[package]] name = "p3-poseidon2-air" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a80481b023f74c0f8ded5058dab8054174e8060d82d400da7b67cf7f2f0a87bc" dependencies = [ "p3-air", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-poseidon2", - "p3-util", - "rand 0.8.5", - "tikv-jemallocator", + "rand 0.9.2", "tracing", ] [[package]] name = "p3-symmetric" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" -dependencies = [ - "itertools 0.14.0", - "p3-field", - "serde", -] - -[[package]] -name = "p3-uni-stark" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a14456a42a7d9e65f13999706f1bca2832175935169b3a54286e18331cf1d82f" dependencies = [ "itertools 0.14.0", - "p3-air", - "p3-challenger", - "p3-commit", - "p3-dft", "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", "serde", - "tracing", ] [[package]] name = "p3-util" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=539bbc84085efb609f4f62cb03cf49588388abdb#539bbc84085efb609f4f62cb03cf49588388abdb" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911154accf66034b0eec4452956c088f92a200b37a8225c1caed74cfbd38cc8d" dependencies = [ "serde", + "transpose", ] [[package]] @@ -6385,15 +5914,6 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - [[package]] name = "poseidon-primitives" version = "0.2.0" @@ -6702,17 +6222,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.17", -] - [[package]] name = "ref-cast" version = "1.0.25" @@ -6779,22 +6288,15 @@ checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64", "bytes", - "encoding_rs", - "futures-channel", "futures-core", - "futures-util", - "h2", "http", "http-body", "http-body-util", "hyper", - "hyper-rustls", "hyper-tls", "hyper-util", "js-sys", "log", - "mime", - "mime_guess", "native-tls", "percent-encoding", "pin-project-lite", @@ -8070,20 +7572,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "ripemd" version = "0.1.3" @@ -8153,7 +7641,7 @@ dependencies = [ "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "parity-scale-codec", @@ -8229,19 +7717,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "rustls" -version = "0.23.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - [[package]] name = "rustls-pki-types" version = "1.13.0" @@ -8251,17 +7726,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-webpki" -version = "0.103.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustversion" version = "1.0.22" @@ -8286,15 +7750,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "sbv-core" version = "2.0.0" @@ -8514,7 +7969,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-build-guest" -version = "0.7.1" +version = "0.8.0" dependencies = [ "cargo_metadata 0.23.1", "clap", @@ -8551,7 +8006,7 @@ version = "0.7.1" dependencies = [ "bincode 2.0.1", "ecies", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.4.3)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", "openvm", "openvm-algebra-complex-macros", "openvm-algebra-guest", @@ -8562,20 +8017,19 @@ dependencies = [ "openvm-pairing-guest", "openvm-rv32im-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.4.3)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", "scroll-zkvm-types-chunk", "scroll-zkvm-types-circuit", ] [[package]] name = "scroll-zkvm-integration" -version = "0.7.1" +version = "0.8.0" dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rpc-client", "alloy-transport", - "axiom-sdk", "base64", "bincode 2.0.1", "bytesize", @@ -8616,7 +8070,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-prover" -version = "0.7.1" +version = "0.8.0" dependencies = [ "base64", "bincode 1.3.3", @@ -8641,7 +8095,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-types" -version = "0.7.1" +version = "0.8.0" dependencies = [ "alloy-primitives", "base64", @@ -8664,7 +8118,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-base" -version = "0.7.1" +version = "0.8.0" dependencies = [ "alloy-primitives", "alloy-serde 1.1.1", @@ -8675,7 +8129,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-batch" -version = "0.7.1" +version = "0.8.0" dependencies = [ "alloy-primitives", "c-kzg", @@ -8695,7 +8149,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-bundle" -version = "0.7.1" +version = "0.8.0" dependencies = [ "scroll-zkvm-types-base", "serde", @@ -8703,7 +8157,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-chunk" -version = "0.7.1" +version = "0.8.0" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8715,12 +8169,12 @@ dependencies = [ "ecies", "hex-literal", "itertools 0.14.0", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.4.3)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", "openvm-ecc-guest", "openvm-pairing", "openvm-pairing-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.4.3)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", "sbv-core", "sbv-helpers", "sbv-primitives", @@ -8732,7 +8186,7 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-circuit" -version = "0.7.1" +version = "0.8.0" dependencies = [ "alloy-primitives", "itertools 0.14.0", @@ -8742,28 +8196,9 @@ dependencies = [ "scroll-zkvm-types-base", ] -[[package]] -name = "scroll-zkvm-upload-axiom" -version = "0.7.1" -dependencies = [ - "axiom-sdk", - "cargo_metadata 0.23.1", - "clap", - "color-eyre", - "console", - "dotenvy", - "eyre", - "hex", - "inquire", - "jiff", - "openvm-sdk", - "scroll-zkvm-types", - "serde_json", -] - [[package]] name = "scroll-zkvm-verifier" -version = "0.7.1" +version = "0.8.0" dependencies = [ "bincode 1.3.3", "eyre", @@ -8905,28 +8340,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde-untagged" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" -dependencies = [ - "erased-serde", - "serde", - "serde_core", - "typeid", -] - -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float 2.10.1", - "serde", -] - [[package]] name = "serde_arrays" version = "0.1.0" @@ -9115,27 +8528,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - [[package]] name = "signal-hook-registry" version = "1.4.6" @@ -9155,12 +8547,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "siphasher" version = "1.0.1" @@ -9205,7 +8591,7 @@ dependencies = [ "hex", "itertools 0.11.0", "lazy_static", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "pairing 0.23.0", @@ -9230,7 +8616,7 @@ dependencies = [ "hex", "itertools 0.11.0", "lazy_static", - "num-bigint 0.4.6", + "num-bigint", "num-integer", "num-traits", "rand 0.8.5", @@ -9256,6 +8642,15 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.3.0" @@ -9448,43 +8843,12 @@ dependencies = [ "windows", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", -] - [[package]] name = "tempfile" version = "3.23.0" @@ -9589,26 +8953,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "tikv-jemalloc-sys" -version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "tikv-jemallocator" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - [[package]] name = "time" version = "0.3.44" @@ -9697,16 +9041,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.17" @@ -9785,7 +9119,6 @@ dependencies = [ "indexmap 2.12.0", "toml_datetime 0.7.3", "toml_parser", - "toml_writer", "winnow", ] @@ -9804,12 +9137,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" -[[package]] -name = "toml_writer" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" - [[package]] name = "tower" version = "0.5.2" @@ -9887,16 +9214,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber 0.3.20", -] - [[package]] name = "tracing-forest" version = "0.1.6" @@ -9985,12 +9302,6 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - [[package]] name = "typenum" version = "1.19.0" @@ -10027,12 +9338,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - [[package]] name = "unicode-ident" version = "1.0.22" @@ -10045,12 +9350,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - [[package]] name = "unicode-xid" version = "0.2.6" @@ -10077,12 +9376,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "unty" version = "0.0.4" @@ -10160,16 +9453,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -10302,15 +9585,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -10348,8 +9622,8 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-result", + "windows-strings", ] [[package]] @@ -10407,17 +9681,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -10427,15 +9690,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link 0.2.1", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -10445,24 +9699,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 1030fdba..e8f14170 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "crates/verifier", "crates/integration", "crates/build-guest", - "crates/tools/upload-axiom", ] resolver = "2" @@ -23,51 +22,51 @@ edition = "2021" homepage = "https://github.com/scroll-tech/zkvm-prover" readme = "README.md" repository = "https://github.com/scroll-tech/zkvm-prover" -version = "0.7.1" +version = "0.8.0" [workspace.dependencies] # openvm guest libs -openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3" } -openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3" } -openvm-sha256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", package = "p256", tag = "v1.4.3", features = [ +openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0" } +openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0" } +openvm-sha256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", package = "p256", features = [ "std", ] } -openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", package = "k256", tag = "v1.4.3", features = [ +openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", package = "k256", features = [ "std", ] } -openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3" } -openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } +openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0" } +openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } # openvm host libs -openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-build = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-native-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-native-compiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-native-recursion = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-native-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } -openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false, features = [ +openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-build = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-native-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-native-compiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-native-recursion = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-native-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false, features = [ "parallel", "evm-prove", "tco", "unprotected" ] } -openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.3", default-features = false } +openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } # more openvm related libs -openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.2.3" } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.4.0" } sbv-core = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2" } sbv-helpers = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["dev"] } @@ -130,7 +129,6 @@ sysinfo = { version = "0.35", default-features = false } bytesize = "2.0.1" url = "2.5.4" tokio = "1" -axiom-sdk = { git = "https://github.com/axiom-crypto/axiom-api-cli.git", tag = "v1.0.10" } dotenvy = "0.15" jiff = "0.2" diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 964e3409..e381e0e2 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -45,7 +45,9 @@ use openvm_sdk::{ fs::write_object_to_file, prover::AppProver, }; -use openvm_stark_sdk::p3_bn254_fr::Bn254Fr; +use openvm_stark_sdk::{ + openvm_stark_backend::p3_field::RawDataSerializable, p3_bn254::Bn254 as Bn254Fr, +}; use scroll_zkvm_types::zkvm::AGG_STARK_PROVING_KEY; use snark_verifier_sdk::snark_verifier::loader::evm::compile_solidity; use std::{ @@ -106,8 +108,7 @@ fn write_commitment_as_evm_hex( commitment: [u32; DIGEST_SIZE], ) -> Result<()> { let digest_bytes = compress_commitment(&commitment) - .value - .to_bytes() + .into_bytes() .into_iter() .rev() // To big endian .collect::>(); @@ -359,7 +360,12 @@ fn generate_openvm_assets( env::set_current_dir(workspace_dir)?; generate_root_verifier(workspace_dir, force_overwrite)?; - generate_evm_verifier(&release_output_dir.join("verifier"), false, force_overwrite)?; + let recompute_mode = env::var("RECOMPUTE_MODE").is_ok_and(|value| value == "yes"); + generate_evm_verifier( + &release_output_dir.join("verifier"), + recompute_mode, + force_overwrite, + )?; Ok(()) } diff --git a/crates/build-guest/src/verifier.rs b/crates/build-guest/src/verifier.rs index cef94d57..ba8dbcb2 100644 --- a/crates/build-guest/src/verifier.rs +++ b/crates/build-guest/src/verifier.rs @@ -48,7 +48,7 @@ pub fn generate_evm_verifier() -> Result { } pub fn download_evm_verifier() -> Result { - let openvm_version = "v1.4"; + let openvm_version = "v1.6"; let verifier_url = format!( "https://github.com/openvm-org/openvm-solidity-sdk/raw/refs/heads/main/src/{openvm_version}/Halo2Verifier.sol" ); diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index a56fd9bc..ec58aa4e 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1323428575, 739444403, 975817221, 1884376082, 1869082474, 301119364, 847692461, 1689905020]; +pub const COMMIT: [u32; 8] = [842060827, 993500768, 936440349, 1604245966, 1912443431, 1241897626, 1534466364, 971236353]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 44734bac..f0a1c137 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1143979762, 1252839784, 728295280, 80130475, 1981604375, 1538642995, 55047256, 1521517292]; +pub const COMMIT: [u32; 8] = [184413583, 817213459, 1770545230, 506082644, 392636437, 394603732, 701963897, 1903551595]; diff --git a/crates/circuits/batch-circuit/openvm.toml b/crates/circuits/batch-circuit/openvm.toml index 3222ad82..57f20c6d 100644 --- a/crates/circuits/batch-circuit/openvm.toml +++ b/crates/circuits/batch-circuit/openvm.toml @@ -2,7 +2,8 @@ log_blowup = 1 log_final_poly_len = 0 num_queries = 100 -proof_of_work_bits = 16 +commit_proof_of_work_bits = 16 +query_proof_of_work_bits = 16 [app_vm_config.rv32i] diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 8d845f4e..f592022e 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [395255096, 1538461738, 1900404427, 924047718, 794880083, 331615215, 287045005, 551525680]; +pub const COMMIT: [u32; 8] = [1315991861, 1159051020, 1956221458, 955647964, 575299566, 340530118, 657814792, 1613011968]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 5271f85c..035fad35 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [702922786, 974900043, 1870917533, 1628966797, 1650497578, 697799835, 298481193, 1937656708]; +pub const COMMIT: [u32; 8] = [1617351029, 1079883676, 762946113, 10192143, 226678694, 624048814, 1296673833, 289380029]; diff --git a/crates/circuits/bundle-circuit/openvm.toml b/crates/circuits/bundle-circuit/openvm.toml index 2aa640c8..a727c8fc 100644 --- a/crates/circuits/bundle-circuit/openvm.toml +++ b/crates/circuits/bundle-circuit/openvm.toml @@ -2,7 +2,8 @@ log_blowup = 1 log_final_poly_len = 0 num_queries = 100 -proof_of_work_bits = 16 +commit_proof_of_work_bits = 16 +query_proof_of_work_bits = 16 [app_vm_config.rv32i] diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index d4871ec3..a0d384c0 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [153372445, 1720016086, 1822473630, 946375535, 421518027, 1979460861, 209770256, 812698810]; +pub const COMMIT: [u32; 8] = [1405946550, 948896569, 910747726, 1411602065, 1171035055, 1831827523, 1042456379, 846703479]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index 739a25bf..f5974456 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [636098662, 1159240103, 1476249019, 1206808598, 446929719, 1171493582, 43492796, 756143264]; +pub const COMMIT: [u32; 8] = [1498643758, 1530221351, 234703906, 1968260365, 1545136087, 1171806024, 1188359720, 631440768]; diff --git a/crates/circuits/chunk-circuit/openvm.toml b/crates/circuits/chunk-circuit/openvm.toml index c1463017..b7caf215 100644 --- a/crates/circuits/chunk-circuit/openvm.toml +++ b/crates/circuits/chunk-circuit/openvm.toml @@ -2,7 +2,8 @@ log_blowup = 1 log_final_poly_len = 0 num_queries = 100 -proof_of_work_bits = 16 +commit_proof_of_work_bits = 16 +query_proof_of_work_bits = 16 [app_vm_config.rv32i] diff --git a/crates/integration/Cargo.toml b/crates/integration/Cargo.toml index 5f7c9099..179d701e 100644 --- a/crates/integration/Cargo.toml +++ b/crates/integration/Cargo.toml @@ -58,7 +58,6 @@ regex = "1.11.1" sysinfo = { workspace = true, features = ["system"] } bytesize.workspace = true url.workspace = true -axiom-sdk.workspace = true dotenvy.workspace = true [dev-dependencies] diff --git a/crates/integration/src/axiom.rs b/crates/integration/src/axiom.rs deleted file mode 100644 index a3cac5b5..00000000 --- a/crates/integration/src/axiom.rs +++ /dev/null @@ -1,165 +0,0 @@ -use super::TaskProver; -use axiom_sdk::build::BuildSdk; -use axiom_sdk::config::ConfigSdk; -use axiom_sdk::input::Input; -use axiom_sdk::prove::{ProveArgs, ProveSdk}; -use axiom_sdk::{AxiomConfig, AxiomSdk, ProgressCallback, ProofType}; -use chrono::DateTime; -use openvm_sdk::commit::CommitBytes; -use openvm_sdk::types::{EvmProof, VersionedVmStarkProof}; -use scroll_zkvm_types::ProvingTask as UniversalProvingTask; -use scroll_zkvm_types::axiom::AxiomProgram; -use scroll_zkvm_types::proof::ProofEnum; -use scroll_zkvm_types::types_agg::ProgramCommitment; -use scroll_zkvm_types::utils::serialize_vk; -use std::env; - -pub struct AxiomProver { - name: String, - sdk: AxiomSdk, - program_id: String, -} - -struct TracingProgressCallback; - -impl AxiomProver { - /// Create a new client - pub fn from_env(name: String, program: &AxiomProgram) -> Self { - let api_key = env::var("AXIOM_API_KEY").expect("AXIOM_API_KEY env var is required"); - let config = AxiomConfig { - api_key: Some(api_key), - config_id: Some(program.config_id().to_string()), - ..Default::default() - }; - let sdk = AxiomSdk::new(config).with_callback(TracingProgressCallback); - Self { - name, - sdk, - program_id: program.program_id().to_string(), - } - } - - pub fn get_app_commitment(&mut self) -> eyre::Result { - let vm_commitment = self.sdk.get_vm_config_metadata(None)?.app_vm_commit; - let vm_commitment: [u8; _] = hex::decode(vm_commitment)?.try_into().unwrap(); - let app_exe_commit: [u8; _] = self - .sdk - .get_app_exe_commit(&self.program_id)? - .try_into() - .unwrap(); - - let exe = CommitBytes::new(app_exe_commit).to_u32_digest(); - let vm = CommitBytes::new(vm_commitment).to_u32_digest(); - - Ok(ProgramCommitment { exe, vm }) - } -} - -impl TaskProver for AxiomProver { - fn name(&self) -> &str { - &self.name - } - - fn prove_task(&mut self, t: &UniversalProvingTask, gen_snark: bool) -> eyre::Result { - let input = serde_json::to_value(t.build_openvm_input())?; - - let proof_type = if gen_snark { - ProofType::Evm - } else { - ProofType::Stark - }; - - let job_id = self.sdk.generate_new_proof(ProveArgs { - program_id: Some(self.program_id.clone()), - input: Some(Input::Value(input)), - proof_type: Some(proof_type), - num_gpus: Some(16), - priority: None, - })?; - - let status = self.sdk.wait_for_proof_completion(&job_id, false)?; - if status.state.as_str() != "Succeeded" { - return Err(eyre::eyre!( - "Proof generation failed with status: {}", - status.state - )); - } - tracing::info!(name: "wait_for_proof_completion", "{status:#?}"); - - let cycles = status.num_instructions.unwrap(); - let launched_at = DateTime::parse_from_rfc3339(status.launched_at.as_deref().unwrap())?; - let terminated_at = DateTime::parse_from_rfc3339(status.terminated_at.as_deref().unwrap())?; - let duration = terminated_at - .signed_duration_since(launched_at) - .as_seconds_f64(); - let mhz = cycles as f64 / duration / 1e6f64; - tracing::info!("Proof generated in {duration:.2} seconds: {mhz:.2} MHz"); - - let proof_bytes = self - .sdk - .get_generated_proof(&status.id, &proof_type, None)?; - - match proof_type { - ProofType::Stark => { - let proof: VersionedVmStarkProof = serde_json::from_slice(&proof_bytes)?; - Ok(ProofEnum::Stark( - proof.try_into().expect("Failed to convert to StarkProof"), - )) - } - ProofType::Evm => { - let proof: EvmProof = serde_json::from_slice(&proof_bytes)?; - Ok(ProofEnum::Evm(proof.into())) - } - } - } - - fn get_vk(&mut self) -> eyre::Result> { - Ok(serialize_vk::serialize(&self.get_app_commitment()?)) - } -} - -impl ProgressCallback for TracingProgressCallback { - fn on_header(&self, text: &str) { - tracing::info!("{text}"); - } - - fn on_success(&self, text: &str) { - tracing::info!("{text}"); - } - - fn on_info(&self, text: &str) { - tracing::info!("{text}"); - } - - fn on_warning(&self, text: &str) { - tracing::warn!("{text}"); - } - - fn on_error(&self, text: &str) { - tracing::error!("{text}"); - } - - fn on_section(&self, title: &str) { - tracing::info!("{title}:"); - } - - fn on_field(&self, key: &str, value: &str) { - tracing::info!(" {key}: {value}"); - } - - fn on_status(&self, text: &str) { - tracing::info!("status={text}"); - } - - fn on_progress_start(&self, _message: &str, _total: Option) {} - - fn on_progress_update(&self, _current: u64) {} - - fn on_progress_update_message(&self, _message: &str) {} - - fn on_progress_finish(&self, _message: &str) {} - - fn on_clear_line(&self) {} - - fn on_clear_line_and_reset(&self) {} -} diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 155a298e..8e56f593 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -1,4 +1,3 @@ -use crate::axiom::AxiomProver; use cargo_metadata::MetadataCommand; use once_cell::sync::OnceCell; use openvm_sdk::{Sdk, StdIn}; @@ -7,7 +6,6 @@ use scroll_zkvm_prover::{ setup::{read_app_config, read_app_exe}, utils::{read_json, vm::ExecutionResult, write_json}, }; -use scroll_zkvm_types::axiom::AxiomProgram; use scroll_zkvm_types::{ ProvingTask as UniversalProvingTask, proof::{EvmProof, ProofEnum, StarkProof}, @@ -29,7 +27,6 @@ pub mod testers; pub mod utils; -mod axiom; /// Directory to store proofs on disc. const DIR_PROOFS: &str = "proofs"; @@ -100,15 +97,6 @@ pub static PROGRAM_COMMITMENTS: LazyLock> = commitments }); -pub static AXIOM_PROGRAM_IDS: LazyLock> = LazyLock::new(|| { - let axiom_program_ids = ASSET_BASE_DIR.join("axiom_program_ids.json"); - let mut program_ids: HashMap = - read_json(&axiom_program_ids).expect("failed to read axiom program ids"); - program_ids.shrink_to_fit(); - eprintln!("AXIOM_PROGRAM_IDS = {program_ids:#?}"); - program_ids -}); - /// Every test run will write assets to a new directory. /// /// Possibly one of the following: @@ -213,18 +201,6 @@ pub trait ProverTester { Ok(prover) } - /// Load the axiom program prover - fn load_axiom_prover() -> eyre::Result { - let mut prover = Self::load_prover(false)?; - let vk = prover.get_app_commitment(); - let vk = hex::encode(serialize_vk::serialize(&vk)); - let program = AXIOM_PROGRAM_IDS - .get(&vk) - .ok_or_else(|| eyre::eyre!("missing axiom program id for {}: {}", Self::NAME, vk))?; - let prover = AxiomProver::from_env(Self::NAME.to_string(), program); - Ok(prover) - } - /// File descriptor for the proof saved to disc. #[instrument("Prover::fd_proof", skip_all, fields(task_id = task.identifier(), path_proof))] fn fd_proof(task: &impl PartialProvingTask) -> String { diff --git a/crates/prover/src/setup.rs b/crates/prover/src/setup.rs index 5d408280..d2fecde5 100644 --- a/crates/prover/src/setup.rs +++ b/crates/prover/src/setup.rs @@ -65,8 +65,7 @@ pub fn read_app_exe>(path: P) -> Result, Error> { path: path.as_ref().into(), src: e.to_string(), })?; - use openvm_stark_sdk::openvm_stark_backend::p3_field::FieldAlgebra; - use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField32; + use openvm_stark_sdk::openvm_stark_backend::p3_field::{PrimeField32, integers::QuotientMap}; let exe = VmExe:: { program: Program:: { instructions_and_debug_infos: old_exe.program.instructions_and_debug_infos, @@ -77,7 +76,7 @@ pub fn read_app_exe>(path: P) -> Result, Error> { .init_memory .into_iter() .map(|(k, v)| { - assert!(v < F::from_canonical_u32(256u32)); + assert!(v < F::from_int(256u32)); (k, v.as_canonical_u32() as u8) }) .collect(), diff --git a/crates/types/batch/src/blob_consistency/openvm.rs b/crates/types/batch/src/blob_consistency/openvm.rs index e5d44356..0439b802 100644 --- a/crates/types/batch/src/blob_consistency/openvm.rs +++ b/crates/types/batch/src/blob_consistency/openvm.rs @@ -59,11 +59,14 @@ const VERSIONED_HASH_VERSION_KZG: u8 = 1; /// /// We use [`openvm_pairing_guest`] extension to implement this in guest program. pub fn verify_kzg_proof(z: Scalar, y: Scalar, commitment: G1Affine, proof: G1Affine) -> bool { - let proof_q = G1Affine::from_xy_nonidentity(proof.x().clone(), proof.y().clone()) - .expect("kzg proof not G1 identity"); - let p_minus_y = G1Affine::from_xy_nonidentity(commitment.x().clone(), commitment.y().clone()) - .expect("kzg commitment not G1 identity") - - msm(&[y], std::slice::from_ref(&G1Affine::GENERATOR)); + let proof_q = unsafe { + G1Affine::from_xy_nonidentity(proof.x().clone(), proof.y().clone()) + .expect("kzg proof not G1 identity") + }; + let p_minus_y = unsafe { + G1Affine::from_xy_nonidentity(commitment.x().clone(), commitment.y().clone()) + .expect("kzg commitment not G1 identity") + } - msm(&[y], std::slice::from_ref(&G1Affine::GENERATOR)); let g2_generator: &G2Affine = &G2_GENERATOR; let x_minus_z = msm(&[z], std::slice::from_ref(g2_generator)) - KZG_G2_SETUP.clone(); diff --git a/crates/types/batch/src/blob_consistency/types.rs b/crates/types/batch/src/blob_consistency/types.rs index afac5090..826dfc8b 100644 --- a/crates/types/batch/src/blob_consistency/types.rs +++ b/crates/types/batch/src/blob_consistency/types.rs @@ -27,7 +27,7 @@ impl ToIntrinsic for Bls12_381_G1 { type IntrinsicType = G1Affine; fn to_intrinsic(&self) -> Self::IntrinsicType { - G1Affine::from_xy_unchecked(self.x.to_intrinsic(), self.y.to_intrinsic()) + unsafe { G1Affine::from_xy_unchecked(self.x.to_intrinsic(), self.y.to_intrinsic()) } } } @@ -35,9 +35,11 @@ impl ToIntrinsic for Bls12_381_G2 { type IntrinsicType = G2Affine; fn to_intrinsic(&self) -> Self::IntrinsicType { - G2Affine::from_xy_unchecked( - Fp2::new(self.x.c0.to_intrinsic(), self.x.c1.to_intrinsic()), - Fp2::new(self.y.c0.to_intrinsic(), self.y.c1.to_intrinsic()), - ) + unsafe { + G2Affine::from_xy_unchecked( + Fp2::new(self.x.c0.to_intrinsic(), self.x.c1.to_intrinsic()), + Fp2::new(self.y.c0.to_intrinsic(), self.y.c1.to_intrinsic()), + ) + } } } diff --git a/crates/types/batch/src/witness.rs b/crates/types/batch/src/witness.rs index 22913ca3..fb7e569c 100644 --- a/crates/types/batch/src/witness.rs +++ b/crates/types/batch/src/witness.rs @@ -74,7 +74,7 @@ pub fn build_intrinsic_point( use openvm_pairing::bls12_381::{Fp, G1Affine}; let x = Fp::from_be_bytes(&x)?; let y = Fp::from_be_bytes(&y)?; - G1Affine::from_xy(x, y) + unsafe { G1Affine::from_xy(x, y) } } pub fn build_point(x: Bytes48, y: Bytes48) -> Option { diff --git a/crates/types/chunk/src/crypto/bn254.rs b/crates/types/chunk/src/crypto/bn254.rs index d68062bb..51c3d6ec 100644 --- a/crates/types/chunk/src/crypto/bn254.rs +++ b/crates/types/chunk/src/crypto/bn254.rs @@ -93,7 +93,7 @@ fn read_fq2(input: &[u8]) -> Result { pub(super) fn read_g1_point(input: &[u8]) -> Result { let px = read_fq(&input[0..FQ_LEN])?; let py = read_fq(&input[FQ_LEN..2 * FQ_LEN])?; - G1Affine::from_xy(px, py).ok_or(PrecompileError::Bn254AffineGFailedToCreate) + unsafe { G1Affine::from_xy(px, py).ok_or(PrecompileError::Bn254AffineGFailedToCreate) } } /// Encodes a G1 point into a byte array. @@ -146,7 +146,8 @@ pub(super) fn read_g2_point(input: &[u8]) -> Result { // [`G2Affine::from_xy`] checks that the point is on the curve, but does not check if the point // is in the correct subgroup. - let point = G2Affine::from_xy(ba, bb).ok_or(PrecompileError::Bn254AffineGFailedToCreate)?; + let point = + unsafe { G2Affine::from_xy(ba, bb).ok_or(PrecompileError::Bn254AffineGFailedToCreate)? }; // Perform the subgroup check. // @@ -162,7 +163,7 @@ pub(super) fn read_g2_point(input: &[u8]) -> Result { let p_times_point = { let psi_x = point.x().frobenius_map(1) * &P_POWER_ENDOMORPHISM_COEFF_0; let psi_y = point.y().frobenius_map(1) * &P_POWER_ENDOMORPHISM_COEFF_1; - G2Affine::from_xy_unchecked(psi_x, psi_y) + unsafe { G2Affine::from_xy_unchecked(psi_x, psi_y) } }; x_times_point.eq(&p_times_point) @@ -430,7 +431,7 @@ mod test { let g2_point = { let ba = read_fq2(&point_rep[0..FQ2_LEN]).unwrap(); let bb = read_fq2(&point_rep[FQ2_LEN..2 * FQ2_LEN]).unwrap(); - G2Affine::from_xy(ba, bb).unwrap() + unsafe { G2Affine::from_xy(ba, bb).unwrap() } }; // the input points from ark and ours are identify From bc2c30756845e985f656987da8ba93d0a961ca27 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Mon, 18 May 2026 15:05:58 +0800 Subject: [PATCH 02/19] clean axiom --- crates/integration/tests/batch_circuit.rs | 12 - crates/integration/tests/bundle_circuit.rs | 12 - crates/integration/tests/chunk_circuit.rs | 11 - crates/prover/src/prover/mod.rs | 4 +- crates/tools/upload-axiom/Cargo.toml | 23 -- crates/tools/upload-axiom/src/main.rs | 308 --------------------- 6 files changed, 2 insertions(+), 368 deletions(-) delete mode 100644 crates/tools/upload-axiom/Cargo.toml delete mode 100644 crates/tools/upload-axiom/src/main.rs diff --git a/crates/integration/tests/batch_circuit.rs b/crates/integration/tests/batch_circuit.rs index 3f5331dd..4d8990e4 100644 --- a/crates/integration/tests/batch_circuit.rs +++ b/crates/integration/tests/batch_circuit.rs @@ -69,18 +69,6 @@ fn e2e() -> eyre::Result<()> { Ok(()) } -#[test] -fn axiom_e2e() -> eyre::Result<()> { - BatchProverTester::setup(true)?; - - let mut prover = BatchProverTester::load_axiom_prover()?; - let mut chunk_prover = ChunkProverTester::load_axiom_prover()?; - let mut batch = BatchTaskGenerator::from_chunk_tasks(&preset_chunk_multiple(), None); - let _ = batch.get_or_build_proof(&mut prover, &mut chunk_prover)?; - - Ok(()) -} - #[test] fn verify_batch_hash_invariant() -> eyre::Result<()> { use scroll_zkvm_types::public_inputs::ForkName; diff --git a/crates/integration/tests/bundle_circuit.rs b/crates/integration/tests/bundle_circuit.rs index b829da53..b44d4887 100644 --- a/crates/integration/tests/bundle_circuit.rs +++ b/crates/integration/tests/bundle_circuit.rs @@ -133,18 +133,6 @@ fn e2e() -> eyre::Result<()> { Ok(()) } -#[test] -fn axiom_e2e() -> eyre::Result<()> { - BundleProverTester::setup(true)?; - - let mut chunk_prover = ChunkProverTester::load_axiom_prover()?; - let mut batch_prover = BatchProverTester::load_axiom_prover()?; - let mut bundle_prover = BundleProverTester::load_axiom_prover()?; - e2e_inner(&mut chunk_prover, &mut batch_prover, &mut bundle_prover)?; - - Ok(()) -} - fn e2e_inner( chunk_prover: &mut impl TaskProver, batch_prover: &mut impl TaskProver, diff --git a/crates/integration/tests/chunk_circuit.rs b/crates/integration/tests/chunk_circuit.rs index 0e11162d..649fd5cd 100644 --- a/crates/integration/tests/chunk_circuit.rs +++ b/crates/integration/tests/chunk_circuit.rs @@ -195,17 +195,6 @@ fn setup_prove_verify_single() -> eyre::Result<()> { Ok(()) } -#[test] -fn setup_axiom_prove_verify_single() -> eyre::Result<()> { - ChunkProverTester::setup(true)?; - let mut prover = ChunkProverTester::load_axiom_prover()?; - - let wit = get_witness_from_env_or_builder(&mut preset_chunk())?; - let _ = prove_verify::(&mut prover, &wit, &[])?; - - Ok(()) -} - #[test] fn setup_prove_verify_multi() -> eyre::Result<()> { ChunkProverTester::setup(true)?; diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index e51e166f..e243a1d6 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -89,8 +89,8 @@ impl Prover { fn get_sdk(&self) -> Result<&Sdk, Error> { self.sdk.get_or_try_init(|| { tracing::info!("Lazy initializing SDK..."); - let sdk = Sdk::new(self.app_config.clone()).expect("sdk init failed"); - + let mut sdk = Sdk::new(self.app_config.clone()).expect("sdk init failed"); + sdk.agg_tree_config_mut().num_children_internal = 2; // 45s for first time let sdk = sdk.with_agg_pk(AGG_STARK_PROVING_KEY.clone()); Ok(sdk) diff --git a/crates/tools/upload-axiom/Cargo.toml b/crates/tools/upload-axiom/Cargo.toml deleted file mode 100644 index 5877d6f3..00000000 --- a/crates/tools/upload-axiom/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "scroll-zkvm-upload-axiom" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true - -[dependencies] -axiom-sdk.workspace = true -cargo_metadata.workspace = true -clap = { version = "4.0", features = ["derive"] } -console = "0.16" -dotenvy.workspace = true -color-eyre.workspace = true -eyre.workspace = true -hex.workspace = true -inquire = "0.9" -openvm-sdk.workspace = true -serde_json.workspace = true -scroll-zkvm-types.workspace = true -jiff.workspace = true diff --git a/crates/tools/upload-axiom/src/main.rs b/crates/tools/upload-axiom/src/main.rs deleted file mode 100644 index cc3cf597..00000000 --- a/crates/tools/upload-axiom/src/main.rs +++ /dev/null @@ -1,308 +0,0 @@ -use axiom_sdk::AxiomConfig; -use axiom_sdk::build::{BuildSdk, UploadExeArgs}; -use axiom_sdk::config::ConfigSdk; -use axiom_sdk::projects::ProjectSdk; -use clap::ArgGroup; -use clap::{Parser, ValueEnum}; -use console::{Emoji, style}; -use dotenvy::dotenv; -use eyre::Context; -use inquire::{Confirm, Text}; -use jiff::civil::{DateTime, DateTimeDifference}; -use jiff::tz::TimeZone; -use jiff::{Timestamp, Unit, Zoned}; -use openvm_sdk::commit::CommitBytes; -use scroll_zkvm_types::axiom::{AxiomProgram, get_config_id}; -use scroll_zkvm_types::utils::serialize_vk; -use std::collections::HashMap; -use std::fs::File; -use std::io::{IsTerminal, stderr, stdout}; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::{env, fs}; - -#[derive(Parser)] -#[command(name = "upload-axiom")] -#[command(about = "Upload guest program (chunk, batch, bundle) to Axiom")] -#[command( - group( - ArgGroup::new("project_selection") - .args(&["project_id", "create_project"]) - .required(true) - .multiple(false) - ) -)] -#[command( - group( - ArgGroup::new("program_ids") - .args(&["no_write_ids", "upload_s3"]) - .required(false) - .multiple(false) - ) -)] -struct Cli { - /// Guest program version - /// - /// "dev" or specific version like "0.5.0" - #[arg(short = 'v', long, default_value = "dev", env = "GUEST_VERSION")] - guest_version: String, - /// Projects to upload - /// - /// Comma separated list of "chunk", "batch", "bundle" - #[arg( - short = 'p', - long, - env = "PROJECTS_TO_UPLOAD", - value_delimiter = ',', - default_value = "chunk,batch,bundle" - )] - uploads: Vec, - /// Don't write program ids json - #[arg(long)] - no_write_ids: bool, - /// Uploads program ids json to s3 if available - #[arg(long)] - upload_s3: bool, - - /// The directory containing the manifest of the crate to run this command in. - #[arg(long, env = "CARGO_MANIFEST_DIR")] - manifest_dir: PathBuf, - - /// Axiom API Key - #[arg( - long, - env = "AXIOM_API_KEY", - help_heading = "Axiom Configuration", - hide_env_values = true - )] - api_key: String, - /// Axiom Project ID - #[arg(long, env = "AXIOM_PROJECT_ID", help_heading = "Axiom Configuration")] - project_id: Option, - /// Create new Axiom Project with this name - #[arg(long, help_heading = "Axiom Configuration")] - create_project: Option, - #[arg( - long, - default_value = "https://api.axiom.xyz/v1", - help_heading = "Axiom Configuration" - )] - api_url: String, - - /// Answer yes to all prompts - #[arg(short = 'y', long = "yes", help_heading = "Miscellaneous")] - yes: bool, - /// Dry run mode - #[arg(long, help_heading = "Miscellaneous")] - dry_run: bool, - /// Coloring - #[arg(long, default_value = "auto", help_heading = "Miscellaneous")] - color: ColorChoice, -} - -#[derive(Copy, Clone, ValueEnum, Debug)] -enum ColorChoice { - Auto, - Always, - Never, -} - -const LOG_PREFIX: &str = "[upload-axiom]"; -const OK: Emoji = Emoji("✅", "✓ "); -const WARN: Emoji = Emoji("⚠️", "! "); - -fn main() -> eyre::Result<()> { - // Load .env file if present - dotenv().ok(); - color_eyre::install()?; - - let cli = Cli::parse(); - - match cli.color { - ColorChoice::Always => { - console::set_colors_enabled(true); - console::set_colors_enabled_stderr(true); - } - ColorChoice::Never => { - console::set_colors_enabled(false); - console::set_colors_enabled_stderr(false); - } - _ => {} - } - - // Set current directory to the crate's root - env::set_current_dir(&cli.manifest_dir)?; - - let interactive = stdout().is_terminal() && stderr().is_terminal(); - let assume_yes = cli.yes || !interactive; - - let metadata = cargo_metadata::MetadataCommand::new().no_deps().exec()?; - let workspace_dir = metadata.workspace_root.into_std_path_buf(); - - let guest_version = if interactive { - Text::new("Guest version:") - .with_initial_value(&cli.guest_version) - .prompt()? - } else { - cli.guest_version - }; - - let axiom_config = AxiomConfig { - api_url: cli.api_url, - api_key: Some(cli.api_key), - ..Default::default() - }; - - let sdk = axiom_sdk::AxiomSdk::new(axiom_config.clone()); - - let project_id = if let Some(project_name) = cli.create_project { - let project_id = sdk.create_project(&project_name)?.id; - println!( - "{LOG_PREFIX} {OK} Created new Axiom project '{project_name}' with ID: {project_id}" - ); - project_id - } else { - cli.project_id.unwrap() - }; - - let guest_dir = workspace_dir.join("releases").join(&guest_version); - - let vks: HashMap = serde_json::from_reader( - File::open(guest_dir.join("verifier").join("openVmVk.json")) - .context("Failed to open openVmVk.json")?, - ) - .context("Failed to parse openVmVk.json")?; - - for project in cli.uploads.iter() { - if !vks.contains_key(&format!("{project}_vk")) { - eyre::bail!("Project '{project}' not found in openVmVk.json"); - } - } - - let mut program_ids = HashMap::new(); - - for project in cli.uploads { - let Some(vk) = vks.get(&format!("{project}_vk")) else { - eyre::bail!("Project '{project}' not found in openVmVk.json"); - }; - - let styled_project = style(&project).bold().green(); - let dir = guest_dir.join(&project); - - let config_id = get_config_id(&project); - let sdk = axiom_sdk::AxiomSdk::new(AxiomConfig { - config_id: Some(config_id.to_string()), - ..axiom_config.clone() - }); - - // verify config_id is correct - let commitment = serialize_vk::deserialize(&hex::decode(vk)?); - let vm_commitment = CommitBytes::from_u32_digest(&commitment.vm); - let config_vm_commitment = sdk.get_vm_config_metadata(Some(config_id))?.app_vm_commit; - let config_vm_commitment = hex::decode(config_vm_commitment)?; - if vm_commitment.as_slice() == config_vm_commitment.as_slice() { - println!("{LOG_PREFIX} {OK} config_id VM commitment matches."); - } else { - let abort = assume_yes - || !Confirm::new(&format!( - "{WARN} VM commitment mismatch for project {styled_project}. Continue anyway?" - )) - .with_default(false) - .prompt()?; - if abort { - println!( - "{LOG_PREFIX} {WARN} invalid config_id for project {styled_project}, skipping upload..." - ); - continue; - } - } - - let app_elf = dir.join("app.elf"); - let app_vmexe = dir.join("app.vmexe"); - - // Print metadata for double check - println!("{LOG_PREFIX} Preparing to upload project {styled_project}:"); - print_metadata(&app_elf)?; - print_metadata(&app_vmexe)?; - - let proceed = assume_yes - || Confirm::new(&format!("Proceed to upload {styled_project} to Axiom?")) - .with_default(false) - .prompt()?; - if !proceed { - println!("Skipping upload of {styled_project}"); - continue; - } - - println!("{LOG_PREFIX} Uploading project {styled_project}..."); - - let program_id = sdk.upload_exe_raw( - fs::read(app_elf)?, - fs::read(app_vmexe)?, - UploadExeArgs { - config_id: Some(config_id.to_string()), - project_id: Some(project_id.clone()), - project_name: None, - bin_name: Some(project.clone()), - program_name: Some(project.clone()), - default_num_gpus: None, - }, - )?; - println!( - "{LOG_PREFIX} {OK} Uploaded project {styled_project} with Program ID: {program_id}" - ); - - program_ids.insert(vk, AxiomProgram::new(program_id, config_id)); - } - - if !cli.no_write_ids { - let output_path = guest_dir.join("axiom_program_ids.json"); - fs::write(&output_path, serde_json::to_string_pretty(&program_ids)?)?; - println!( - "{LOG_PREFIX} {OK} Wrote Axiom program IDs to {}", - output_path.display() - ); - - // "s3://circuit-release/scroll-zkvm/releases/$GUEST_VERSION/axiom_program_ids.json" - // aws --profile default s3 cp - if cli.upload_s3 { - let s3_path = format!( - "s3://circuit-release/scroll-zkvm/releases/{guest_version}/axiom_program_ids.json" - ); - let status = Command::new("aws") - .arg("--profile") - .arg("default") - .arg("s3") - .arg("cp") - .arg(output_path) - .arg(&s3_path) - .status()?; - if status.success() { - println!("{LOG_PREFIX} {OK} Uploaded axiom_program_ids.json to {s3_path}"); - } else { - println!( - "{LOG_PREFIX} {WARN} Failed to upload axiom_program_ids.json to {s3_path}" - ); - } - } - } - - Ok(()) -} - -fn print_metadata>(path: P) -> eyre::Result<()> { - let now: DateTime = Zoned::now().into(); - - let name = path.as_ref().file_name().unwrap().to_string_lossy(); - let metadata = fs::metadata(&path)?; - - println!("- {}:", name); - println!(" - size: {} bytes", metadata.len()); - - let created: DateTime = Timestamp::try_from(metadata.created()?)? - .to_zoned(TimeZone::system()) - .into(); - let passed = created.until(DateTimeDifference::new(now).smallest(Unit::Second))?; - println!(" - created: {passed:#} ago ({created:#})"); - Ok(()) -} From 47eaa4cf02543f0f50cc3a9fe9a04b6b24cca14b Mon Sep 17 00:00:00 2001 From: Velaciela Date: Mon, 18 May 2026 20:21:55 +0800 Subject: [PATCH 03/19] fixed --- AGENTS.md | 109 + .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- releases/dev/verifier/verifier.bin | Bin 18545 -> 18558 bytes releases/dev/verifier/verifier.sol | 2032 +++++++++-------- scripts/build-and-run.sh | 5 +- 10 files changed, 1175 insertions(+), 983 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..fff655ad --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,109 @@ +# AGENTS.md — scroll-zkvm-prover + +Critical context for AI agents working on this repo. Read this before making changes, especially around OpenVM upgrades or guest builds. + +## Project Structure + +- **Guest circuits**: `crates/circuits/{chunk,batch,bundle}-circuit/` — RISC-V ELFs compiled to `.vmexe` +- **Build tool**: `crates/build-guest/` — generates guest assets, commitments, verifier contract +- **Host prover**: `crates/prover/` — loads guest executables and runs STARK/SNARK proving +- **Integration tests**: `crates/integration/` — end-to-end tests (chunk → batch → bundle) +- **Asset outputs**: `releases/dev/{chunk,batch,bundle,verifier}/` +- **Test outputs**: `.output/` — cached proofs and intermediate artifacts + +## OpenVM Version Sensitivity + +This project uses **OpenVM** as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: + +- The guest/host data layout (hint streams, public inputs) +- The `root_verifier.asm` format +- The Halo2 SRS degree requirement (e.g. `k=23` → `k=24`) +- The EVM verifier contract ABI +- Field algebra APIs (`from_canonical_u32` → `from_int`) +- ECC constructor signatures (some became `unsafe`) + +### After ANY OpenVM version upgrade, you MUST: + +1. **Update the hardcoded version string** in `crates/build-guest/src/verifier.rs`: + ```rust + let openvm_version = "v1.6"; // MUST match Cargo.toml git rev + ``` + +2. **Force-rebuild ALL guest assets** (auto mode skips existing files): + ```bash + cargo run --release -p scroll-zkvm-build-guest -- --mode force + ``` + This regenerates: `app.elf`, `app.vmexe`, `root_verifier.asm`, commitment `.rs` files, and `openVmVk.json`. + +3. **Verify commitments were updated** — check that `*_exe_commit.rs` and `*_vm_commit.rs` files changed, and that `openVmVk.json` timestamps are fresh. + +4. **Clear global OpenVM caches** in `~/.openvm/`: + ```bash + rm -f ~/.openvm/agg_stark.pk ~/.openvm/agg_stark.vk ~/.openvm/root.asm + ``` + These are cached proving keys. They are **not** automatically invalidated on version bumps. + +5. **Check SRS params** in `~/.openvm/params/`: + - OpenVM v1.5.0+ requires `kzg_bn254_24.srs` (2 GB) + - Earlier versions used `kzg_bn254_23.srs` (1 GB) + - If the file is empty/corrupted, replace it (check for `.1` or `.part` suffixes from interrupted downloads) + +6. **Clear test output cache** before re-running integration tests: + ```bash + rm -rf .output/bundle-tests-*/ + ``` + Integration tests reuse cached proofs by default. Stale proofs from a previous OpenVM version will cause failures. + +## Common Failure Patterns + +### `NativeHintSliceSubEx` assertion failure +``` +assertion left == right failed (left: 21, right: 1) +``` +**Cause**: Stale guest assets (`app.vmexe` or `root_verifier.asm`) from a previous OpenVM version. +**Fix**: Follow all 6 steps above. + +### `UnexpectedEof` in `CacheHalo2ParamsReader::read_params` +``` +UnexpectedEof: failed to fill whole buffer +``` +**Cause**: `~/.openvm/params/kzg_bn254_24.srs` is missing, empty, or truncated. +**Fix**: Ensure a valid 2 GB SRS file exists at that exact path. + +### Docker build fails with stale CID +The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. Use local build (`cargo run -p scroll-zkvm-build-guest`) as fallback. + +## Build & Test Commands + +```bash +# Force rebuild all guest assets (required after OpenVM upgrade) +cargo run --release -p scroll-zkvm-build-guest -- --mode force + +# Run end-to-end tests (ALWAYS use make, never raw cargo test) +GPU=1 make test-e2e-bundle +GPU=1 make test-e2e-batch +GPU=1 make test-e2e-chunk +``` + +**⚠️ CRITICAL: Always use `make` for integration tests.** +The Makefile sets `RUST_MIN_STACK=16777216` (16 MB) and `CARGO_CONFIG_FLAG`. Running `cargo test` directly skips both, which causes: +- Stack overflow during prover initialization (default Rust stack is only ~2 MB) +- Missing CUDA features if `GPU=1` is set but `--features scroll-zkvm-integration/cuda` is not passed + +## Important File Paths + +| File / Dir | Purpose | +|------------|---------| +| `releases/dev/{chunk,batch,bundle}/app.vmexe` | Guest executables | +| `releases/dev/verifier/openVmVk.json` | Program commitments loaded by integration tests | +| `crates/circuits/*-circuit/openvm.toml` | Guest VM configs (FRI params, PoW bits) | +| `crates/circuits/*-circuit/commitments.rs` | Hardcoded commitment arrays | +| `~/.openvm/params/kzg_bn254_24.srs` | Halo2 KZG SRS (2 GB) | +| `~/.openvm/agg_stark.{pk,vk}` | Cached aggregation proving/verifying keys | +| `.output/` | Integration test outputs (proofs, intermediate files) | + +## Guest Config Notes + +- `chunk-circuit`: requires `system.config.continuation_enabled = true` +- `batch-circuit` / `bundle-circuit`: include `leaf_fri_params` with `num_queries = 193`, `commit_proof_of_work_bits = 20` +- FRI params format changed in OpenVM 1.6.0: `proof_of_work_bits` → `commit_proof_of_work_bits` + `query_proof_of_work_bits` diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index ec58aa4e..85bacd94 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [842060827, 993500768, 936440349, 1604245966, 1912443431, 1241897626, 1534466364, 971236353]; +pub const COMMIT: [u32; 8] = [574520761, 879677804, 1283141277, 1761929109, 1721107250, 974282683, 435330475, 625449777]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index f0a1c137..73b57247 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [184413583, 817213459, 1770545230, 506082644, 392636437, 394603732, 701963897, 1903551595]; +pub const COMMIT: [u32; 8] = [1792226047, 611100767, 1146270814, 1810005845, 1491201797, 1214999763, 783504632, 1498168266]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index f592022e..0df06713 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1315991861, 1159051020, 1956221458, 955647964, 575299566, 340530118, 657814792, 1613011968]; +pub const COMMIT: [u32; 8] = [516873274, 1075607986, 1001047012, 1209458940, 427908064, 1922052567, 1750380191, 1968279532]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 035fad35..e346add1 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1617351029, 1079883676, 762946113, 10192143, 226678694, 624048814, 1296673833, 289380029]; +pub const COMMIT: [u32; 8] = [925169990, 1379116760, 1021966620, 1957896599, 611090420, 136189529, 1819023587, 441111398]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index a0d384c0..cc204f47 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1405946550, 948896569, 910747726, 1411602065, 1171035055, 1831827523, 1042456379, 846703479]; +pub const COMMIT: [u32; 8] = [748412756, 309489192, 1741755255, 1877282487, 564318861, 1368414247, 704142321, 1392145592]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index f5974456..2de70f52 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1498643758, 1530221351, 234703906, 1968260365, 1545136087, 1171806024, 1188359720, 631440768]; +pub const COMMIT: [u32; 8] = [1467589762, 470654227, 683360028, 597448633, 205292274, 1767305327, 1252880894, 241340940]; diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin index 6b35e16d6dd671f2919298047e2ca45462b2d39e..667bbebe71d6e2c1bb976f24a400ef2fbd38940a 100644 GIT binary patch literal 18558 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 OfWBQDNbdep)&B?b(< literal 18545 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 diff --git a/releases/dev/verifier/verifier.sol b/releases/dev/verifier/verifier.sol index c0f46233..c6b5cef7 100644 --- a/releases/dev/verifier/verifier.sol +++ b/releases/dev/verifier/verifier.sol @@ -7,7 +7,9 @@ contract Halo2Verifier { assembly ("memory-safe") { // Enforce that Solidity memory layout is respected let data := mload(0x40) - if iszero(eq(data, 0x80)) { revert(0, 0) } + if iszero(eq(data, 0x80)) { + revert(0, 0) + } let success := true let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 @@ -75,7 +77,7 @@ contract Halo2Verifier { mstore(0x600, mod(calldataload(0x560), f_q)) mstore(0x620, mod(calldataload(0x580), f_q)) mstore(0x640, mod(calldataload(0x5a0), f_q)) - mstore(0x80, 390330814115173750526380320564184081440196244988022584520359727231485894627) + mstore(0x80, 3099200876874169560829918599785312545415625616099245974171476775798883330872) { let x := calldataload(0x5c0) @@ -288,1239 +290,1314 @@ contract Halo2Verifier { mstore(0x11c0, mulmod(mload(0x11a0), mload(0x11a0), f_q)) mstore(0x11e0, mulmod(mload(0x11c0), mload(0x11c0), f_q)) mstore(0x1200, mulmod(mload(0x11e0), mload(0x11e0), f_q)) + mstore(0x1220, mulmod(mload(0x1200), mload(0x1200), f_q)) mstore( - 0x1220, + 0x1240, addmod( - mload(0x1200), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q + mload(0x1220), + 21888242871839275222246405745257275088548364400416034343698204186575808495616, + f_q ) ) mstore( - 0x1240, + 0x1260, mulmod( - mload(0x1220), 21888240262557392955334514970720457388010314637169927192662615958087340972065, f_q + mload(0x1240), + 21888241567198334088790460357988866238279339518792980768180410072331574733841, + f_q ) ) - mstore( - 0x1260, - mulmod(mload(0x1240), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q) - ) mstore( 0x1280, - addmod(mload(0xa80), 17381407133017170883578305204439900340613258090403036486730017014837178292110, f_q) + mulmod( + mload(0x1260), + 12929131318670223636853686797196826072950305380535537217467769528748593133487, + f_q + ) ) mstore( 0x12a0, - mulmod( - mload(0x1240), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q - ) + addmod(mload(0xa80), 8959111553169051585392718948060449015598059019880497126230434657827215362130, f_q) ) mstore( 0x12c0, - addmod(mload(0xa80), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q) + mulmod( + mload(0x1260), + 14655294445420895451632927078981340937842238432098198055057679026789553137428, + f_q + ) ) mstore( 0x12e0, - mulmod(mload(0x1240), 1887003188133998471169152042388914354640772748308168868301418279904560637395, f_q) + addmod(mload(0xa80), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q) ) mstore( 0x1300, - addmod(mload(0xa80), 20001239683705276751077253702868360733907591652107865475396785906671247858222, f_q) + mulmod( + mload(0x1260), + 12220484078924208264862893648548198807365556694478604924193442790112568454894, + f_q + ) ) mstore( 0x1320, - mulmod(mload(0x1240), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q) + addmod(mload(0xa80), 9667758792915066957383512096709076281182807705937429419504761396463240040723, f_q) ) mstore( 0x1340, - addmod(mload(0xa80), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q) + mulmod(mload(0x1260), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q) ) mstore( 0x1360, - mulmod( - mload(0x1240), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q - ) + addmod(mload(0xa80), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q) ) mstore( 0x1380, - addmod(mload(0xa80), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q) + mulmod(mload(0x1260), 7358966525675286471217089135633860168646304224547606326237275077574224349359, f_q) ) mstore( 0x13a0, - mulmod(mload(0x1240), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q) + addmod(mload(0xa80), 14529276346163988751029316609623414919902060175868428017460929109001584146258, f_q) ) mstore( 0x13c0, - addmod(mload(0xa80), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q) + mulmod(mload(0x1260), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q) ) mstore( 0x13e0, - mulmod(mload(0x1240), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q) + addmod(mload(0xa80), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q) ) mstore( 0x1400, - addmod(mload(0xa80), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q) + mulmod( + mload(0x1260), + 17329448237240114492580865744088056414251735686965494637158808787419781175510, + f_q + ) ) - mstore(0x1420, mulmod(mload(0x1240), 1, f_q)) mstore( - 0x1440, - addmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q) + 0x1420, + addmod(mload(0xa80), 4558794634599160729665540001169218674296628713450539706539395399156027320107, f_q) ) + mstore(0x1440, mulmod(mload(0x1260), 1, f_q)) mstore( 0x1460, - mulmod(mload(0x1240), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) + addmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q) ) mstore( 0x1480, - addmod(mload(0xa80), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q) + mulmod( + mload(0x1260), + 11451405578697956743456240853980216273390554734748796433026540431386972584651, + f_q + ) ) mstore( 0x14a0, - mulmod( - mload(0x1240), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q - ) + addmod(mload(0xa80), 10436837293141318478790164891277058815157809665667237910671663755188835910966, f_q) ) mstore( 0x14c0, - addmod(mload(0xa80), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q) + mulmod(mload(0x1260), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) ) mstore( 0x14e0, - mulmod(mload(0x1240), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q) + addmod(mload(0xa80), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q) ) mstore( 0x1500, - addmod(mload(0xa80), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q) + mulmod( + mload(0x1260), + 21490807004895109926141140246143262403290679459142140821740925192625185504522, + f_q + ) ) mstore( 0x1520, - mulmod(mload(0x1240), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q) + addmod(mload(0xa80), 397435866944165296105265499114012685257684941273893521957278993950622991095, f_q) ) mstore( 0x1540, - addmod(mload(0xa80), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q) + mulmod( + mload(0x1260), + 11211301017135681023579411905410872569206244553457844956874280139879520583390, + f_q + ) ) mstore( 0x1560, - mulmod(mload(0x1240), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q) + addmod(mload(0xa80), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q) ) mstore( 0x1580, - addmod(mload(0xa80), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q) + mulmod( + mload(0x1260), + 18846108080730935585192484934247867403156699586319724728525857970312957475341, + f_q + ) ) mstore( 0x15a0, - mulmod( - mload(0x1240), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q - ) + addmod(mload(0xa80), 3042134791108339637053920811009407685391664814096309615172346216262851020276, f_q) ) mstore( 0x15c0, - addmod(mload(0xa80), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q) + mulmod(mload(0x1260), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q) ) mstore( 0x15e0, - mulmod( - mload(0x1240), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q - ) + addmod(mload(0xa80), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q) ) mstore( 0x1600, - addmod(mload(0xa80), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q) + mulmod( + mload(0x1260), + 21451937155080765789602997556105366785934335730087568134349216848800867145453, + f_q + ) ) mstore( 0x1620, - mulmod( - mload(0x1240), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q - ) + addmod(mload(0xa80), 436305716758509432643408189151908302614028670328466209348987337774941350164, f_q) ) mstore( 0x1640, - addmod(mload(0xa80), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q) + mulmod(mload(0x1260), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q) ) mstore( 0x1660, - mulmod( - mload(0x1240), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q - ) + addmod(mload(0xa80), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q) ) mstore( 0x1680, - addmod(mload(0xa80), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q) + mulmod( + mload(0x1260), + 13982290267294411190096162596630216412723378687553046594730793425118513274800, + f_q + ) ) mstore( 0x16a0, - mulmod(mload(0x1240), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q) + addmod(mload(0xa80), 7905952604544864032150243148627058675824985712862987748967410761457295220817, f_q) ) mstore( 0x16c0, - addmod(mload(0xa80), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q) + mulmod(mload(0x1260), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q) ) mstore( 0x16e0, - mulmod(mload(0x1240), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q) + addmod(mload(0xa80), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q) ) mstore( 0x1700, - addmod(mload(0xa80), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q) + mulmod(mload(0x1260), 9537783784440837896026284659246718978615447564543116209283382057778110278482, f_q) ) mstore( 0x1720, - mulmod(mload(0x1240), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q) + addmod(mload(0xa80), 12350459087398437326220121086010556109932916835872918134414822128797698217135, f_q) ) mstore( 0x1740, - addmod(mload(0xa80), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q) + mulmod( + mload(0x1260), + 12619617507853212586156872920672483948819476989779550311307282715684870266992, + f_q + ) ) mstore( 0x1760, - mulmod(mload(0x1240), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q) + addmod(mload(0xa80), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q) ) mstore( 0x1780, - addmod(mload(0xa80), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q) + mulmod(mload(0x1260), 3947443723575973965644279767310964219908423994086470065513888332899718123222, f_q) ) mstore( 0x17a0, - mulmod(mload(0x1240), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q) + addmod(mload(0xa80), 17940799148263301256602125977946310868639940406329564278184315853676090372395, f_q) ) mstore( 0x17c0, - addmod(mload(0xa80), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q) + mulmod( + mload(0x1260), + 18610195890048912503953886742825279624920778288956610528523679659246523534888, + f_q + ) ) mstore( 0x17e0, - mulmod(mload(0x1240), 6132660129994545119218258312491950835441607143741804980633129304664017206141, f_q) + addmod(mload(0xa80), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q) ) mstore( 0x1800, - addmod(mload(0xa80), 15755582741844730103028147432765324253106757256674229363065074881911791289476, f_q) + mulmod(mload(0x1260), 1539082509056298927655194235755440186888826897239928178265486731666142403222, f_q) ) mstore( 0x1820, - mulmod(mload(0x1240), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q) + addmod(mload(0xa80), 20349160362782976294591211509501834901659537503176106165432717454909666092395, f_q) ) mstore( 0x1840, - addmod(mload(0xa80), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q) + mulmod( + mload(0x1260), + 19032961837237948602743626455740240236231119053033140765040043513661803148152, + f_q + ) ) mstore( 0x1860, - mulmod(mload(0x1240), 515148244606945972463850631189471072103916690263705052318085725998468254533, f_q) + addmod(mload(0xa80), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q) ) mstore( 0x1880, - addmod(mload(0xa80), 21373094627232329249782555114067804016444447710152329291380118460577340241084, f_q) + mulmod(mload(0x1260), 4317410353320599552056040796202302907960891408523818766419977508859423800635, f_q) ) mstore( 0x18a0, - mulmod(mload(0x1240), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q) + addmod(mload(0xa80), 17570832518518675670190364949054972180587472991892215577278226677716384694982, f_q) ) mstore( 0x18c0, - addmod(mload(0xa80), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q) + mulmod( + mload(0x1260), + 14875928112196239563830800280253496262679717528621719058794366823499719730250, + f_q + ) ) mstore( 0x18e0, - mulmod(mload(0x1240), 5223738580615264174925218065001555728265216895679471490312087802465486318994, f_q) + addmod(mload(0xa80), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q) ) mstore( 0x1900, - addmod(mload(0xa80), 16664504291224011047321187680255719360283147504736562853386116384110322176623, f_q) + mulmod(mload(0x1260), 2366023502186770334390939928726871658997402416352868340984630739442624219298, f_q) ) mstore( 0x1920, - mulmod( - mload(0x1240), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q - ) + addmod(mload(0xa80), 19522219369652504887855465816530403429550961984063166002713573447133184276319, f_q) ) mstore( 0x1940, - addmod(mload(0xa80), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q) + mulmod(mload(0x1260), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q) ) mstore( 0x1960, - mulmod( - mload(0x1240), 16976236069879939850923145256911338076234942200101755618884183331004076579046, f_q - ) + addmod(mload(0xa80), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q) ) mstore( 0x1980, - addmod(mload(0xa80), 4912006801959335371323260488345937012313422200314278724814020855571731916571, f_q) + mulmod( + mload(0x1260), + 14391499717548074167711220639833994904150450341569029103202493919171555826079, + f_q + ) ) mstore( 0x19a0, - mulmod( - mload(0x1240), 13553911191894110065493137367144919847521088405945523452288398666974237857208, f_q - ) + addmod(mload(0xa80), 7496743154291201054535185105423280184397914058847005240495710267404252669538, f_q) ) mstore( 0x19c0, - addmod(mload(0xa80), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q) + mulmod(mload(0x1260), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q) ) mstore( 0x19e0, - mulmod( - mload(0x1240), 12222687719926148270818604386979005738180875192307070468454582955273533101023, f_q - ) + addmod(mload(0xa80), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q) ) mstore( 0x1a00, - addmod(mload(0xa80), 9665555151913126951427801358278269350367489208108963875243621231302275394594, f_q) + mulmod( + mload(0x1260), + 10119780362642123194334092174270235809557798114544683654677907882314807212354, + f_q + ) ) mstore( 0x1a20, - mulmod(mload(0x1240), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q) + addmod(mload(0xa80), 11768462509197152027912313570987039278990566285871350689020296304261001283263, f_q) ) mstore( 0x1a40, - addmod(mload(0xa80), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q) + mulmod(mload(0x1260), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q) ) mstore( 0x1a60, - mulmod( - mload(0x1240), 13783318220968413117070077848579881425001701814458176881760898225529300547844, f_q - ) + addmod(mload(0xa80), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q) ) mstore( 0x1a80, - addmod(mload(0xa80), 8104924650870862105176327896677393663546662585957857461937305961046507947773, f_q) + mulmod(mload(0x1260), 2080322550956715654503104356805349981348621877591103674778333538652571537127, f_q) ) mstore( 0x1aa0, - mulmod( - mload(0x1240), 10807735674816066981985242612061336605021639643453679977988966079770672437131, f_q - ) + addmod(mload(0xa80), 19807920320882559567743301388451925107199742522824930668919870647923236958490, f_q) ) mstore( 0x1ac0, - addmod(mload(0xa80), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q) + mulmod(mload(0x1260), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q) ) mstore( 0x1ae0, - mulmod( - mload(0x1240), 15487660954688013862248478071816391715224351867581977083810729441220383572585, f_q - ) + addmod(mload(0xa80), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q) ) mstore( 0x1b00, - addmod(mload(0xa80), 6400581917151261359997927673440883373324012532834057259887474745355424923032, f_q) + mulmod( + mload(0x1260), + 11145214675344139457514777444556774698911688619991656085001542609383151586084, + f_q + ) ) mstore( 0x1b20, - mulmod( - mload(0x1240), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q - ) + addmod(mload(0xa80), 10743028196495135764731628300700500389636675780424378258696661577192656909533, f_q) ) mstore( 0x1b40, - addmod(mload(0xa80), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q) + mulmod(mload(0x1260), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q) ) mstore( 0x1b60, - mulmod( - mload(0x1240), 12562571400845953139885120066983392294851269266041089223701347829190217414825, f_q - ) + addmod(mload(0xa80), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q) ) mstore( 0x1b80, - addmod(mload(0xa80), 9325671470993322082361285678273882793697095134374945119996856357385591080792, f_q) + mulmod( + mload(0x1260), + 19228510170961893342195489288913594506775385223367826565223897736323409650249, + f_q + ) ) mstore( 0x1ba0, - mulmod( - mload(0x1240), 16038300751658239075779628684257016433412502747804121525056508685985277092575, f_q - ) + addmod(mload(0xa80), 2659732700877381880050916456343680581772979177048207778474306450252398845368, f_q) ) mstore( 0x1bc0, - addmod(mload(0xa80), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q) + mulmod(mload(0x1260), 6132660129994545119218258312491950835441607143741804980633129304664017206141, f_q) ) mstore( 0x1be0, - mulmod( - mload(0x1240), 17665522928519859765452767154433594409738037332395989540221744312194874941704, f_q - ) + addmod(mload(0xa80), 15755582741844730103028147432765324253106757256674229363065074881911791289476, f_q) ) mstore( 0x1c00, - addmod(mload(0xa80), 4222719943319415456793638590823680678810327068020044803476459874380933553913, f_q) + mulmod( + mload(0x1260), + 10094752117139066216691253588991632982053223883646966177987813353508871280747, + f_q + ) ) mstore( 0x1c20, - mulmod(mload(0x1240), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q) + addmod(mload(0xa80), 11793490754700209005555152156265642106495140516769068165710390833066937214870, f_q) ) mstore( 0x1c40, - addmod(mload(0xa80), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q) + mulmod(mload(0x1260), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q) ) mstore( 0x1c60, - mulmod(mload(0x1240), 1918679275621049296283934091410967415474987212511681231948800935495808101054, f_q) + addmod(mload(0xa80), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q) ) mstore( 0x1c80, - addmod(mload(0xa80), 19969563596218225925962471653846307673073377187904353111749403251080000394563, f_q) + mulmod( + mload(0x1260), + 21346203717540287263608402129024479709126363130664317843105498655869866203005, + f_q + ) ) mstore( 0x1ca0, - mulmod( - mload(0x1240), 13498745591877810872211159461644682954739332524336278910448604883789771736885, f_q - ) + addmod(mload(0xa80), 542039154298987958638003616232795379422001269751716500592705530705942292612, f_q) ) mstore( 0x1cc0, - addmod(mload(0xa80), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q) + mulmod(mload(0x1260), 515148244606945972463850631189471072103916690263705052318085725998468254533, f_q) ) mstore( 0x1ce0, - mulmod(mload(0x1240), 6604851689411953560355663038203889299997924520355363678860500374111951937637, f_q) + addmod(mload(0xa80), 21373094627232329249782555114067804016444447710152329291380118460577340241084, f_q) ) mstore( 0x1d00, - addmod(mload(0xa80), 15283391182427321661890742707053385788550439880060670664837703812463856557980, f_q) + mulmod( + mload(0x1260), + 13788243025932779125104144225768424453664118806559109014238064020826883170336, + f_q + ) ) mstore( 0x1d20, - mulmod( - mload(0x1240), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q - ) + addmod(mload(0xa80), 8099999845906496097142261519488850634884245593856925329460140165748925325281, f_q) ) mstore( 0x1d40, - addmod(mload(0xa80), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q) + mulmod(mload(0x1260), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q) ) mstore( 0x1d60, - mulmod( - mload(0x1240), 11244009323710436498447061620026171700033960328162115124806024297270121927878, f_q - ) + addmod(mload(0xa80), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q) ) mstore( 0x1d80, - addmod(mload(0xa80), 10644233548128838723799344125231103388514404072253919218892179889305686567739, f_q) + mulmod(mload(0x1260), 8561696234966975469289029207282849740510759316794581475824569334969644143582, f_q) ) mstore( 0x1da0, - mulmod(mload(0x1240), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q) + addmod(mload(0xa80), 13326546636872299752957376537974425348037605083621452867873634851606164352035, f_q) ) mstore( 0x1dc0, - addmod(mload(0xa80), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q) + mulmod(mload(0x1260), 5223738580615264174925218065001555728265216895679471490312087802465486318994, f_q) ) mstore( 0x1de0, - mulmod( - mload(0x1240), 13894403229372218245111098554468346933152618215322268934207074514797092422856, f_q - ) + addmod(mload(0xa80), 16664504291224011047321187680255719360283147504736562853386116384110322176623, f_q) ) mstore( 0x1e00, - addmod(mload(0xa80), 7993839642467056977135307190788928155395746185093765409491129671778716072761, f_q) + mulmod(mload(0x1260), 3302268277365219249160464068848832456250192077357408622723420445620736662125, f_q) ) mstore( 0x1e20, - mulmod(mload(0x1240), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q) + addmod(mload(0xa80), 18585974594474055973085941676408442632298172323058625720974783740955071833492, f_q) ) mstore( 0x1e40, - addmod(mload(0xa80), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q) + mulmod( + mload(0x1260), + 14557038802599140430182096396825290815503940951075961210638273254419942783582, + f_q + ) ) mstore( 0x1e60, - mulmod( - mload(0x1240), 19715528266218439644661892824912275086257866064695767122686506494361332681035, f_q - ) + addmod(mload(0xa80), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q) ) mstore( 0x1e80, - addmod(mload(0xa80), 2172714605620835577584512920345000002290498335720267221011697692214475814582, f_q) + mulmod( + mload(0x1260), + 21631349642691366221117117325940229443266870213711402446456178962469345982255, + f_q + ) ) mstore( 0x1ea0, - mulmod( - mload(0x1240), 15161189183906287273290738379431332336600234154579306802151507052820126345529, f_q - ) + addmod(mload(0xa80), 256893229147909001129288419317045645281494186704631897242025224106462513362, f_q) ) mstore( 0x1ec0, - addmod(mload(0xa80), 6727053687932987948955667365825942751948130245836727541546697133755682150088, f_q) + mulmod( + mload(0x1260), + 16976236069879939850923145256911338076234942200101755618884183331004076579046, + f_q + ) ) mstore( 0x1ee0, - mulmod( - mload(0x1240), 12456424076401232823832128238027368612265814450984711658287606686035629293382, f_q - ) + addmod(mload(0xa80), 4912006801959335371323260488345937012313422200314278724814020855571731916571, f_q) ) mstore( 0x1f00, - addmod(mload(0xa80), 9431818795438042398414277507229906476282549949431322685410597500540179202235, f_q) + mulmod( + mload(0x1260), + 18106030913818996184930975996483865250387924434749113154514488995517615180373, + f_q + ) ) mstore( 0x1f20, - mulmod(mload(0x1240), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q) + addmod(mload(0xa80), 3782211958020279037315429748773409838160439965666921189183715191058193315244, f_q) ) mstore( 0x1f40, - addmod(mload(0xa80), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q) + mulmod( + mload(0x1260), + 13553911191894110065493137367144919847521088405945523452288398666974237857208, + f_q + ) ) mstore( 0x1f60, - mulmod(mload(0x1240), 3675353143102618619098608207619541954347747556257261634661810167705798540391, f_q) + addmod(mload(0xa80), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q) ) mstore( 0x1f80, - addmod(mload(0xa80), 18212889728736656603147797537637733134200616844158772709036394018870009955226, f_q) + mulmod( + mload(0x1260), + 15126807493918544618788554261654793824894621953586710625413511093368555507114, + f_q + ) + ) + mstore( + 0x1fa0, + addmod(mload(0xa80), 6761435377920730603457851483602481263653742446829323718284693093207252988503, f_q) ) { - let prod := mload(0x1280) - - prod := mulmod(mload(0x12c0), prod, f_q) - mstore(0x1fa0, prod) + let prod := mload(0x12a0) - prod := mulmod(mload(0x1300), prod, f_q) + prod := mulmod(mload(0x12e0), prod, f_q) mstore(0x1fc0, prod) - prod := mulmod(mload(0x1340), prod, f_q) + prod := mulmod(mload(0x1320), prod, f_q) mstore(0x1fe0, prod) - prod := mulmod(mload(0x1380), prod, f_q) + prod := mulmod(mload(0x1360), prod, f_q) mstore(0x2000, prod) - prod := mulmod(mload(0x13c0), prod, f_q) + prod := mulmod(mload(0x13a0), prod, f_q) mstore(0x2020, prod) - prod := mulmod(mload(0x1400), prod, f_q) + prod := mulmod(mload(0x13e0), prod, f_q) mstore(0x2040, prod) - prod := mulmod(mload(0x1440), prod, f_q) + prod := mulmod(mload(0x1420), prod, f_q) mstore(0x2060, prod) - prod := mulmod(mload(0x1480), prod, f_q) + prod := mulmod(mload(0x1460), prod, f_q) mstore(0x2080, prod) - prod := mulmod(mload(0x14c0), prod, f_q) + prod := mulmod(mload(0x14a0), prod, f_q) mstore(0x20a0, prod) - prod := mulmod(mload(0x1500), prod, f_q) + prod := mulmod(mload(0x14e0), prod, f_q) mstore(0x20c0, prod) - prod := mulmod(mload(0x1540), prod, f_q) + prod := mulmod(mload(0x1520), prod, f_q) mstore(0x20e0, prod) - prod := mulmod(mload(0x1580), prod, f_q) + prod := mulmod(mload(0x1560), prod, f_q) mstore(0x2100, prod) - prod := mulmod(mload(0x15c0), prod, f_q) + prod := mulmod(mload(0x15a0), prod, f_q) mstore(0x2120, prod) - prod := mulmod(mload(0x1600), prod, f_q) + prod := mulmod(mload(0x15e0), prod, f_q) mstore(0x2140, prod) - prod := mulmod(mload(0x1640), prod, f_q) + prod := mulmod(mload(0x1620), prod, f_q) mstore(0x2160, prod) - prod := mulmod(mload(0x1680), prod, f_q) + prod := mulmod(mload(0x1660), prod, f_q) mstore(0x2180, prod) - prod := mulmod(mload(0x16c0), prod, f_q) + prod := mulmod(mload(0x16a0), prod, f_q) mstore(0x21a0, prod) - prod := mulmod(mload(0x1700), prod, f_q) + prod := mulmod(mload(0x16e0), prod, f_q) mstore(0x21c0, prod) - prod := mulmod(mload(0x1740), prod, f_q) + prod := mulmod(mload(0x1720), prod, f_q) mstore(0x21e0, prod) - prod := mulmod(mload(0x1780), prod, f_q) + prod := mulmod(mload(0x1760), prod, f_q) mstore(0x2200, prod) - prod := mulmod(mload(0x17c0), prod, f_q) + prod := mulmod(mload(0x17a0), prod, f_q) mstore(0x2220, prod) - prod := mulmod(mload(0x1800), prod, f_q) + prod := mulmod(mload(0x17e0), prod, f_q) mstore(0x2240, prod) - prod := mulmod(mload(0x1840), prod, f_q) + prod := mulmod(mload(0x1820), prod, f_q) mstore(0x2260, prod) - prod := mulmod(mload(0x1880), prod, f_q) + prod := mulmod(mload(0x1860), prod, f_q) mstore(0x2280, prod) - prod := mulmod(mload(0x18c0), prod, f_q) + prod := mulmod(mload(0x18a0), prod, f_q) mstore(0x22a0, prod) - prod := mulmod(mload(0x1900), prod, f_q) + prod := mulmod(mload(0x18e0), prod, f_q) mstore(0x22c0, prod) - prod := mulmod(mload(0x1940), prod, f_q) + prod := mulmod(mload(0x1920), prod, f_q) mstore(0x22e0, prod) - prod := mulmod(mload(0x1980), prod, f_q) + prod := mulmod(mload(0x1960), prod, f_q) mstore(0x2300, prod) - prod := mulmod(mload(0x19c0), prod, f_q) + prod := mulmod(mload(0x19a0), prod, f_q) mstore(0x2320, prod) - prod := mulmod(mload(0x1a00), prod, f_q) + prod := mulmod(mload(0x19e0), prod, f_q) mstore(0x2340, prod) - prod := mulmod(mload(0x1a40), prod, f_q) + prod := mulmod(mload(0x1a20), prod, f_q) mstore(0x2360, prod) - prod := mulmod(mload(0x1a80), prod, f_q) + prod := mulmod(mload(0x1a60), prod, f_q) mstore(0x2380, prod) - prod := mulmod(mload(0x1ac0), prod, f_q) + prod := mulmod(mload(0x1aa0), prod, f_q) mstore(0x23a0, prod) - prod := mulmod(mload(0x1b00), prod, f_q) + prod := mulmod(mload(0x1ae0), prod, f_q) mstore(0x23c0, prod) - prod := mulmod(mload(0x1b40), prod, f_q) + prod := mulmod(mload(0x1b20), prod, f_q) mstore(0x23e0, prod) - prod := mulmod(mload(0x1b80), prod, f_q) + prod := mulmod(mload(0x1b60), prod, f_q) mstore(0x2400, prod) - prod := mulmod(mload(0x1bc0), prod, f_q) + prod := mulmod(mload(0x1ba0), prod, f_q) mstore(0x2420, prod) - prod := mulmod(mload(0x1c00), prod, f_q) + prod := mulmod(mload(0x1be0), prod, f_q) mstore(0x2440, prod) - prod := mulmod(mload(0x1c40), prod, f_q) + prod := mulmod(mload(0x1c20), prod, f_q) mstore(0x2460, prod) - prod := mulmod(mload(0x1c80), prod, f_q) + prod := mulmod(mload(0x1c60), prod, f_q) mstore(0x2480, prod) - prod := mulmod(mload(0x1cc0), prod, f_q) + prod := mulmod(mload(0x1ca0), prod, f_q) mstore(0x24a0, prod) - prod := mulmod(mload(0x1d00), prod, f_q) + prod := mulmod(mload(0x1ce0), prod, f_q) mstore(0x24c0, prod) - prod := mulmod(mload(0x1d40), prod, f_q) + prod := mulmod(mload(0x1d20), prod, f_q) mstore(0x24e0, prod) - prod := mulmod(mload(0x1d80), prod, f_q) + prod := mulmod(mload(0x1d60), prod, f_q) mstore(0x2500, prod) - prod := mulmod(mload(0x1dc0), prod, f_q) + prod := mulmod(mload(0x1da0), prod, f_q) mstore(0x2520, prod) - prod := mulmod(mload(0x1e00), prod, f_q) + prod := mulmod(mload(0x1de0), prod, f_q) mstore(0x2540, prod) - prod := mulmod(mload(0x1e40), prod, f_q) + prod := mulmod(mload(0x1e20), prod, f_q) mstore(0x2560, prod) - prod := mulmod(mload(0x1e80), prod, f_q) + prod := mulmod(mload(0x1e60), prod, f_q) mstore(0x2580, prod) - prod := mulmod(mload(0x1ec0), prod, f_q) + prod := mulmod(mload(0x1ea0), prod, f_q) mstore(0x25a0, prod) - prod := mulmod(mload(0x1f00), prod, f_q) + prod := mulmod(mload(0x1ee0), prod, f_q) mstore(0x25c0, prod) - prod := mulmod(mload(0x1f40), prod, f_q) + prod := mulmod(mload(0x1f20), prod, f_q) mstore(0x25e0, prod) - prod := mulmod(mload(0x1f80), prod, f_q) + prod := mulmod(mload(0x1f60), prod, f_q) mstore(0x2600, prod) - prod := mulmod(mload(0x1220), prod, f_q) + prod := mulmod(mload(0x1fa0), prod, f_q) mstore(0x2620, prod) + + prod := mulmod(mload(0x1240), prod, f_q) + mstore(0x2640, prod) } - mstore(0x2660, 32) mstore(0x2680, 32) mstore(0x26a0, 32) - mstore(0x26c0, mload(0x2620)) - mstore(0x26e0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x2700, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x2660, 0xc0, 0x2640, 0x20), 1), success) + mstore(0x26c0, 32) + mstore(0x26e0, mload(0x2640)) + mstore(0x2700, 21888242871839275222246405745257275088548364400416034343698204186575808495615) + mstore(0x2720, 21888242871839275222246405745257275088548364400416034343698204186575808495617) + success := and(eq(staticcall(gas(), 0x5, 0x2680, 0xc0, 0x2660, 0x20), 1), success) { - let inv := mload(0x2640) + let inv := mload(0x2660) let v - v := mload(0x1220) - mstore(4640, mulmod(mload(0x2600), inv, f_q)) + v := mload(0x1240) + mstore(4672, mulmod(mload(0x2620), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1f80) - mstore(8064, mulmod(mload(0x25e0), inv, f_q)) + v := mload(0x1fa0) + mstore(8096, mulmod(mload(0x2600), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1f40) - mstore(8000, mulmod(mload(0x25c0), inv, f_q)) + v := mload(0x1f60) + mstore(8032, mulmod(mload(0x25e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1f00) - mstore(7936, mulmod(mload(0x25a0), inv, f_q)) + v := mload(0x1f20) + mstore(7968, mulmod(mload(0x25c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1ec0) - mstore(7872, mulmod(mload(0x2580), inv, f_q)) + v := mload(0x1ee0) + mstore(7904, mulmod(mload(0x25a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1e80) - mstore(7808, mulmod(mload(0x2560), inv, f_q)) + v := mload(0x1ea0) + mstore(7840, mulmod(mload(0x2580), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1e40) - mstore(7744, mulmod(mload(0x2540), inv, f_q)) + v := mload(0x1e60) + mstore(7776, mulmod(mload(0x2560), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1e00) - mstore(7680, mulmod(mload(0x2520), inv, f_q)) + v := mload(0x1e20) + mstore(7712, mulmod(mload(0x2540), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1dc0) - mstore(7616, mulmod(mload(0x2500), inv, f_q)) + v := mload(0x1de0) + mstore(7648, mulmod(mload(0x2520), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1d80) - mstore(7552, mulmod(mload(0x24e0), inv, f_q)) + v := mload(0x1da0) + mstore(7584, mulmod(mload(0x2500), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1d40) - mstore(7488, mulmod(mload(0x24c0), inv, f_q)) + v := mload(0x1d60) + mstore(7520, mulmod(mload(0x24e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1d00) - mstore(7424, mulmod(mload(0x24a0), inv, f_q)) + v := mload(0x1d20) + mstore(7456, mulmod(mload(0x24c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1cc0) - mstore(7360, mulmod(mload(0x2480), inv, f_q)) + v := mload(0x1ce0) + mstore(7392, mulmod(mload(0x24a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1c80) - mstore(7296, mulmod(mload(0x2460), inv, f_q)) + v := mload(0x1ca0) + mstore(7328, mulmod(mload(0x2480), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1c40) - mstore(7232, mulmod(mload(0x2440), inv, f_q)) + v := mload(0x1c60) + mstore(7264, mulmod(mload(0x2460), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1c00) - mstore(7168, mulmod(mload(0x2420), inv, f_q)) + v := mload(0x1c20) + mstore(7200, mulmod(mload(0x2440), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1bc0) - mstore(7104, mulmod(mload(0x2400), inv, f_q)) + v := mload(0x1be0) + mstore(7136, mulmod(mload(0x2420), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1b80) - mstore(7040, mulmod(mload(0x23e0), inv, f_q)) + v := mload(0x1ba0) + mstore(7072, mulmod(mload(0x2400), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1b40) - mstore(6976, mulmod(mload(0x23c0), inv, f_q)) + v := mload(0x1b60) + mstore(7008, mulmod(mload(0x23e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1b00) - mstore(6912, mulmod(mload(0x23a0), inv, f_q)) + v := mload(0x1b20) + mstore(6944, mulmod(mload(0x23c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1ac0) - mstore(6848, mulmod(mload(0x2380), inv, f_q)) + v := mload(0x1ae0) + mstore(6880, mulmod(mload(0x23a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1a80) - mstore(6784, mulmod(mload(0x2360), inv, f_q)) + v := mload(0x1aa0) + mstore(6816, mulmod(mload(0x2380), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1a40) - mstore(6720, mulmod(mload(0x2340), inv, f_q)) + v := mload(0x1a60) + mstore(6752, mulmod(mload(0x2360), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1a00) - mstore(6656, mulmod(mload(0x2320), inv, f_q)) + v := mload(0x1a20) + mstore(6688, mulmod(mload(0x2340), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x19c0) - mstore(6592, mulmod(mload(0x2300), inv, f_q)) + v := mload(0x19e0) + mstore(6624, mulmod(mload(0x2320), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1980) - mstore(6528, mulmod(mload(0x22e0), inv, f_q)) + v := mload(0x19a0) + mstore(6560, mulmod(mload(0x2300), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1940) - mstore(6464, mulmod(mload(0x22c0), inv, f_q)) + v := mload(0x1960) + mstore(6496, mulmod(mload(0x22e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1900) - mstore(6400, mulmod(mload(0x22a0), inv, f_q)) + v := mload(0x1920) + mstore(6432, mulmod(mload(0x22c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x18c0) - mstore(6336, mulmod(mload(0x2280), inv, f_q)) + v := mload(0x18e0) + mstore(6368, mulmod(mload(0x22a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1880) - mstore(6272, mulmod(mload(0x2260), inv, f_q)) + v := mload(0x18a0) + mstore(6304, mulmod(mload(0x2280), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1840) - mstore(6208, mulmod(mload(0x2240), inv, f_q)) + v := mload(0x1860) + mstore(6240, mulmod(mload(0x2260), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1800) - mstore(6144, mulmod(mload(0x2220), inv, f_q)) + v := mload(0x1820) + mstore(6176, mulmod(mload(0x2240), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x17c0) - mstore(6080, mulmod(mload(0x2200), inv, f_q)) + v := mload(0x17e0) + mstore(6112, mulmod(mload(0x2220), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1780) - mstore(6016, mulmod(mload(0x21e0), inv, f_q)) + v := mload(0x17a0) + mstore(6048, mulmod(mload(0x2200), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1740) - mstore(5952, mulmod(mload(0x21c0), inv, f_q)) + v := mload(0x1760) + mstore(5984, mulmod(mload(0x21e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1700) - mstore(5888, mulmod(mload(0x21a0), inv, f_q)) + v := mload(0x1720) + mstore(5920, mulmod(mload(0x21c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x16c0) - mstore(5824, mulmod(mload(0x2180), inv, f_q)) + v := mload(0x16e0) + mstore(5856, mulmod(mload(0x21a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1680) - mstore(5760, mulmod(mload(0x2160), inv, f_q)) + v := mload(0x16a0) + mstore(5792, mulmod(mload(0x2180), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1640) - mstore(5696, mulmod(mload(0x2140), inv, f_q)) + v := mload(0x1660) + mstore(5728, mulmod(mload(0x2160), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1600) - mstore(5632, mulmod(mload(0x2120), inv, f_q)) + v := mload(0x1620) + mstore(5664, mulmod(mload(0x2140), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x15c0) - mstore(5568, mulmod(mload(0x2100), inv, f_q)) + v := mload(0x15e0) + mstore(5600, mulmod(mload(0x2120), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1580) - mstore(5504, mulmod(mload(0x20e0), inv, f_q)) + v := mload(0x15a0) + mstore(5536, mulmod(mload(0x2100), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1540) - mstore(5440, mulmod(mload(0x20c0), inv, f_q)) + v := mload(0x1560) + mstore(5472, mulmod(mload(0x20e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1500) - mstore(5376, mulmod(mload(0x20a0), inv, f_q)) + v := mload(0x1520) + mstore(5408, mulmod(mload(0x20c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x14c0) - mstore(5312, mulmod(mload(0x2080), inv, f_q)) + v := mload(0x14e0) + mstore(5344, mulmod(mload(0x20a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1480) - mstore(5248, mulmod(mload(0x2060), inv, f_q)) + v := mload(0x14a0) + mstore(5280, mulmod(mload(0x2080), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1440) - mstore(5184, mulmod(mload(0x2040), inv, f_q)) + v := mload(0x1460) + mstore(5216, mulmod(mload(0x2060), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1400) - mstore(5120, mulmod(mload(0x2020), inv, f_q)) + v := mload(0x1420) + mstore(5152, mulmod(mload(0x2040), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x13c0) - mstore(5056, mulmod(mload(0x2000), inv, f_q)) + v := mload(0x13e0) + mstore(5088, mulmod(mload(0x2020), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1380) - mstore(4992, mulmod(mload(0x1fe0), inv, f_q)) + v := mload(0x13a0) + mstore(5024, mulmod(mload(0x2000), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1340) - mstore(4928, mulmod(mload(0x1fc0), inv, f_q)) + v := mload(0x1360) + mstore(4960, mulmod(mload(0x1fe0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x1300) - mstore(4864, mulmod(mload(0x1fa0), inv, f_q)) + v := mload(0x1320) + mstore(4896, mulmod(mload(0x1fc0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x12c0) - mstore(4800, mulmod(mload(0x1280), inv, f_q)) + v := mload(0x12e0) + mstore(4832, mulmod(mload(0x12a0), inv, f_q)) inv := mulmod(v, inv, f_q) - mstore(0x1280, inv) + mstore(0x12a0, inv) } - mstore(0x2720, mulmod(mload(0x1260), mload(0x1280), f_q)) - mstore(0x2740, mulmod(mload(0x12a0), mload(0x12c0), f_q)) - mstore(0x2760, mulmod(mload(0x12e0), mload(0x1300), f_q)) - mstore(0x2780, mulmod(mload(0x1320), mload(0x1340), f_q)) - mstore(0x27a0, mulmod(mload(0x1360), mload(0x1380), f_q)) - mstore(0x27c0, mulmod(mload(0x13a0), mload(0x13c0), f_q)) - mstore(0x27e0, mulmod(mload(0x13e0), mload(0x1400), f_q)) - mstore(0x2800, mulmod(mload(0x1420), mload(0x1440), f_q)) - mstore(0x2820, mulmod(mload(0x1460), mload(0x1480), f_q)) - mstore(0x2840, mulmod(mload(0x14a0), mload(0x14c0), f_q)) - mstore(0x2860, mulmod(mload(0x14e0), mload(0x1500), f_q)) - mstore(0x2880, mulmod(mload(0x1520), mload(0x1540), f_q)) - mstore(0x28a0, mulmod(mload(0x1560), mload(0x1580), f_q)) - mstore(0x28c0, mulmod(mload(0x15a0), mload(0x15c0), f_q)) - mstore(0x28e0, mulmod(mload(0x15e0), mload(0x1600), f_q)) - mstore(0x2900, mulmod(mload(0x1620), mload(0x1640), f_q)) - mstore(0x2920, mulmod(mload(0x1660), mload(0x1680), f_q)) - mstore(0x2940, mulmod(mload(0x16a0), mload(0x16c0), f_q)) - mstore(0x2960, mulmod(mload(0x16e0), mload(0x1700), f_q)) - mstore(0x2980, mulmod(mload(0x1720), mload(0x1740), f_q)) - mstore(0x29a0, mulmod(mload(0x1760), mload(0x1780), f_q)) - mstore(0x29c0, mulmod(mload(0x17a0), mload(0x17c0), f_q)) - mstore(0x29e0, mulmod(mload(0x17e0), mload(0x1800), f_q)) - mstore(0x2a00, mulmod(mload(0x1820), mload(0x1840), f_q)) - mstore(0x2a20, mulmod(mload(0x1860), mload(0x1880), f_q)) - mstore(0x2a40, mulmod(mload(0x18a0), mload(0x18c0), f_q)) - mstore(0x2a60, mulmod(mload(0x18e0), mload(0x1900), f_q)) - mstore(0x2a80, mulmod(mload(0x1920), mload(0x1940), f_q)) - mstore(0x2aa0, mulmod(mload(0x1960), mload(0x1980), f_q)) - mstore(0x2ac0, mulmod(mload(0x19a0), mload(0x19c0), f_q)) - mstore(0x2ae0, mulmod(mload(0x19e0), mload(0x1a00), f_q)) - mstore(0x2b00, mulmod(mload(0x1a20), mload(0x1a40), f_q)) - mstore(0x2b20, mulmod(mload(0x1a60), mload(0x1a80), f_q)) - mstore(0x2b40, mulmod(mload(0x1aa0), mload(0x1ac0), f_q)) - mstore(0x2b60, mulmod(mload(0x1ae0), mload(0x1b00), f_q)) - mstore(0x2b80, mulmod(mload(0x1b20), mload(0x1b40), f_q)) - mstore(0x2ba0, mulmod(mload(0x1b60), mload(0x1b80), f_q)) - mstore(0x2bc0, mulmod(mload(0x1ba0), mload(0x1bc0), f_q)) - mstore(0x2be0, mulmod(mload(0x1be0), mload(0x1c00), f_q)) - mstore(0x2c00, mulmod(mload(0x1c20), mload(0x1c40), f_q)) - mstore(0x2c20, mulmod(mload(0x1c60), mload(0x1c80), f_q)) - mstore(0x2c40, mulmod(mload(0x1ca0), mload(0x1cc0), f_q)) - mstore(0x2c60, mulmod(mload(0x1ce0), mload(0x1d00), f_q)) - mstore(0x2c80, mulmod(mload(0x1d20), mload(0x1d40), f_q)) - mstore(0x2ca0, mulmod(mload(0x1d60), mload(0x1d80), f_q)) - mstore(0x2cc0, mulmod(mload(0x1da0), mload(0x1dc0), f_q)) - mstore(0x2ce0, mulmod(mload(0x1de0), mload(0x1e00), f_q)) - mstore(0x2d00, mulmod(mload(0x1e20), mload(0x1e40), f_q)) - mstore(0x2d20, mulmod(mload(0x1e60), mload(0x1e80), f_q)) - mstore(0x2d40, mulmod(mload(0x1ea0), mload(0x1ec0), f_q)) - mstore(0x2d60, mulmod(mload(0x1ee0), mload(0x1f00), f_q)) - mstore(0x2d80, mulmod(mload(0x1f20), mload(0x1f40), f_q)) - mstore(0x2da0, mulmod(mload(0x1f60), mload(0x1f80), f_q)) + mstore(0x2740, mulmod(mload(0x1280), mload(0x12a0), f_q)) + mstore(0x2760, mulmod(mload(0x12c0), mload(0x12e0), f_q)) + mstore(0x2780, mulmod(mload(0x1300), mload(0x1320), f_q)) + mstore(0x27a0, mulmod(mload(0x1340), mload(0x1360), f_q)) + mstore(0x27c0, mulmod(mload(0x1380), mload(0x13a0), f_q)) + mstore(0x27e0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) + mstore(0x2800, mulmod(mload(0x1400), mload(0x1420), f_q)) + mstore(0x2820, mulmod(mload(0x1440), mload(0x1460), f_q)) + mstore(0x2840, mulmod(mload(0x1480), mload(0x14a0), f_q)) + mstore(0x2860, mulmod(mload(0x14c0), mload(0x14e0), f_q)) + mstore(0x2880, mulmod(mload(0x1500), mload(0x1520), f_q)) + mstore(0x28a0, mulmod(mload(0x1540), mload(0x1560), f_q)) + mstore(0x28c0, mulmod(mload(0x1580), mload(0x15a0), f_q)) + mstore(0x28e0, mulmod(mload(0x15c0), mload(0x15e0), f_q)) + mstore(0x2900, mulmod(mload(0x1600), mload(0x1620), f_q)) + mstore(0x2920, mulmod(mload(0x1640), mload(0x1660), f_q)) + mstore(0x2940, mulmod(mload(0x1680), mload(0x16a0), f_q)) + mstore(0x2960, mulmod(mload(0x16c0), mload(0x16e0), f_q)) + mstore(0x2980, mulmod(mload(0x1700), mload(0x1720), f_q)) + mstore(0x29a0, mulmod(mload(0x1740), mload(0x1760), f_q)) + mstore(0x29c0, mulmod(mload(0x1780), mload(0x17a0), f_q)) + mstore(0x29e0, mulmod(mload(0x17c0), mload(0x17e0), f_q)) + mstore(0x2a00, mulmod(mload(0x1800), mload(0x1820), f_q)) + mstore(0x2a20, mulmod(mload(0x1840), mload(0x1860), f_q)) + mstore(0x2a40, mulmod(mload(0x1880), mload(0x18a0), f_q)) + mstore(0x2a60, mulmod(mload(0x18c0), mload(0x18e0), f_q)) + mstore(0x2a80, mulmod(mload(0x1900), mload(0x1920), f_q)) + mstore(0x2aa0, mulmod(mload(0x1940), mload(0x1960), f_q)) + mstore(0x2ac0, mulmod(mload(0x1980), mload(0x19a0), f_q)) + mstore(0x2ae0, mulmod(mload(0x19c0), mload(0x19e0), f_q)) + mstore(0x2b00, mulmod(mload(0x1a00), mload(0x1a20), f_q)) + mstore(0x2b20, mulmod(mload(0x1a40), mload(0x1a60), f_q)) + mstore(0x2b40, mulmod(mload(0x1a80), mload(0x1aa0), f_q)) + mstore(0x2b60, mulmod(mload(0x1ac0), mload(0x1ae0), f_q)) + mstore(0x2b80, mulmod(mload(0x1b00), mload(0x1b20), f_q)) + mstore(0x2ba0, mulmod(mload(0x1b40), mload(0x1b60), f_q)) + mstore(0x2bc0, mulmod(mload(0x1b80), mload(0x1ba0), f_q)) + mstore(0x2be0, mulmod(mload(0x1bc0), mload(0x1be0), f_q)) + mstore(0x2c00, mulmod(mload(0x1c00), mload(0x1c20), f_q)) + mstore(0x2c20, mulmod(mload(0x1c40), mload(0x1c60), f_q)) + mstore(0x2c40, mulmod(mload(0x1c80), mload(0x1ca0), f_q)) + mstore(0x2c60, mulmod(mload(0x1cc0), mload(0x1ce0), f_q)) + mstore(0x2c80, mulmod(mload(0x1d00), mload(0x1d20), f_q)) + mstore(0x2ca0, mulmod(mload(0x1d40), mload(0x1d60), f_q)) + mstore(0x2cc0, mulmod(mload(0x1d80), mload(0x1da0), f_q)) + mstore(0x2ce0, mulmod(mload(0x1dc0), mload(0x1de0), f_q)) + mstore(0x2d00, mulmod(mload(0x1e00), mload(0x1e20), f_q)) + mstore(0x2d20, mulmod(mload(0x1e40), mload(0x1e60), f_q)) + mstore(0x2d40, mulmod(mload(0x1e80), mload(0x1ea0), f_q)) + mstore(0x2d60, mulmod(mload(0x1ec0), mload(0x1ee0), f_q)) + mstore(0x2d80, mulmod(mload(0x1f00), mload(0x1f20), f_q)) + mstore(0x2da0, mulmod(mload(0x1f40), mload(0x1f60), f_q)) + mstore(0x2dc0, mulmod(mload(0x1f80), mload(0x1fa0), f_q)) { - let result := mulmod(mload(0x2800), mload(0xa0), f_q) - result := addmod(mulmod(mload(0x2820), mload(0xc0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2840), mload(0xe0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2860), mload(0x100), f_q), result, f_q) - result := addmod(mulmod(mload(0x2880), mload(0x120), f_q), result, f_q) - result := addmod(mulmod(mload(0x28a0), mload(0x140), f_q), result, f_q) - result := addmod(mulmod(mload(0x28c0), mload(0x160), f_q), result, f_q) - result := addmod(mulmod(mload(0x28e0), mload(0x180), f_q), result, f_q) - result := addmod(mulmod(mload(0x2900), mload(0x1a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2920), mload(0x1c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2940), mload(0x1e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2960), mload(0x200), f_q), result, f_q) - result := addmod(mulmod(mload(0x2980), mload(0x220), f_q), result, f_q) - result := addmod(mulmod(mload(0x29a0), mload(0x240), f_q), result, f_q) - result := addmod(mulmod(mload(0x29c0), mload(0x260), f_q), result, f_q) - result := addmod(mulmod(mload(0x29e0), mload(0x280), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a00), mload(0x2a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a20), mload(0x2c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a40), mload(0x2e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a60), mload(0x300), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a80), mload(0x320), f_q), result, f_q) - result := addmod(mulmod(mload(0x2aa0), mload(0x340), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ac0), mload(0x360), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ae0), mload(0x380), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b00), mload(0x3a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b20), mload(0x3c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b40), mload(0x3e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b60), mload(0x400), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b80), mload(0x420), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ba0), mload(0x440), f_q), result, f_q) - result := addmod(mulmod(mload(0x2bc0), mload(0x460), f_q), result, f_q) - result := addmod(mulmod(mload(0x2be0), mload(0x480), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c00), mload(0x4a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c20), mload(0x4c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c40), mload(0x4e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c60), mload(0x500), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c80), mload(0x520), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ca0), mload(0x540), f_q), result, f_q) - result := addmod(mulmod(mload(0x2cc0), mload(0x560), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ce0), mload(0x580), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d00), mload(0x5a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d20), mload(0x5c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d40), mload(0x5e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d60), mload(0x600), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d80), mload(0x620), f_q), result, f_q) - result := addmod(mulmod(mload(0x2da0), mload(0x640), f_q), result, f_q) - mstore(11712, result) + let result := mulmod(mload(0x2820), mload(0xa0), f_q) + result := addmod(mulmod(mload(0x2840), mload(0xc0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2860), mload(0xe0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2880), mload(0x100), f_q), result, f_q) + result := addmod(mulmod(mload(0x28a0), mload(0x120), f_q), result, f_q) + result := addmod(mulmod(mload(0x28c0), mload(0x140), f_q), result, f_q) + result := addmod(mulmod(mload(0x28e0), mload(0x160), f_q), result, f_q) + result := addmod(mulmod(mload(0x2900), mload(0x180), f_q), result, f_q) + result := addmod(mulmod(mload(0x2920), mload(0x1a0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2940), mload(0x1c0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2960), mload(0x1e0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2980), mload(0x200), f_q), result, f_q) + result := addmod(mulmod(mload(0x29a0), mload(0x220), f_q), result, f_q) + result := addmod(mulmod(mload(0x29c0), mload(0x240), f_q), result, f_q) + result := addmod(mulmod(mload(0x29e0), mload(0x260), f_q), result, f_q) + result := addmod(mulmod(mload(0x2a00), mload(0x280), f_q), result, f_q) + result := addmod(mulmod(mload(0x2a20), mload(0x2a0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2a40), mload(0x2c0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2a60), mload(0x2e0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2a80), mload(0x300), f_q), result, f_q) + result := addmod(mulmod(mload(0x2aa0), mload(0x320), f_q), result, f_q) + result := addmod(mulmod(mload(0x2ac0), mload(0x340), f_q), result, f_q) + result := addmod(mulmod(mload(0x2ae0), mload(0x360), f_q), result, f_q) + result := addmod(mulmod(mload(0x2b00), mload(0x380), f_q), result, f_q) + result := addmod(mulmod(mload(0x2b20), mload(0x3a0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2b40), mload(0x3c0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2b60), mload(0x3e0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2b80), mload(0x400), f_q), result, f_q) + result := addmod(mulmod(mload(0x2ba0), mload(0x420), f_q), result, f_q) + result := addmod(mulmod(mload(0x2bc0), mload(0x440), f_q), result, f_q) + result := addmod(mulmod(mload(0x2be0), mload(0x460), f_q), result, f_q) + result := addmod(mulmod(mload(0x2c00), mload(0x480), f_q), result, f_q) + result := addmod(mulmod(mload(0x2c20), mload(0x4a0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2c40), mload(0x4c0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2c60), mload(0x4e0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2c80), mload(0x500), f_q), result, f_q) + result := addmod(mulmod(mload(0x2ca0), mload(0x520), f_q), result, f_q) + result := addmod(mulmod(mload(0x2cc0), mload(0x540), f_q), result, f_q) + result := addmod(mulmod(mload(0x2ce0), mload(0x560), f_q), result, f_q) + result := addmod(mulmod(mload(0x2d00), mload(0x580), f_q), result, f_q) + result := addmod(mulmod(mload(0x2d20), mload(0x5a0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2d40), mload(0x5c0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2d60), mload(0x5e0), f_q), result, f_q) + result := addmod(mulmod(mload(0x2d80), mload(0x600), f_q), result, f_q) + result := addmod(mulmod(mload(0x2da0), mload(0x620), f_q), result, f_q) + result := addmod(mulmod(mload(0x2dc0), mload(0x640), f_q), result, f_q) + mstore(11744, result) } - mstore(0x2de0, mulmod(mload(0xb00), mload(0xae0), f_q)) - mstore(0x2e00, addmod(mload(0xac0), mload(0x2de0), f_q)) - mstore(0x2e20, addmod(mload(0x2e00), sub(f_q, mload(0xb20)), f_q)) - mstore(0x2e40, mulmod(mload(0x2e20), mload(0xb80), f_q)) - mstore(0x2e60, mulmod(mload(0x920), mload(0x2e40), f_q)) - mstore(0x2e80, addmod(1, sub(f_q, mload(0xc40)), f_q)) - mstore(0x2ea0, mulmod(mload(0x2e80), mload(0x2800), f_q)) - mstore(0x2ec0, addmod(mload(0x2e60), mload(0x2ea0), f_q)) - mstore(0x2ee0, mulmod(mload(0x920), mload(0x2ec0), f_q)) - mstore(0x2f00, mulmod(mload(0xc40), mload(0xc40), f_q)) - mstore(0x2f20, addmod(mload(0x2f00), sub(f_q, mload(0xc40)), f_q)) - mstore(0x2f40, mulmod(mload(0x2f20), mload(0x2720), f_q)) - mstore(0x2f60, addmod(mload(0x2ee0), mload(0x2f40), f_q)) - mstore(0x2f80, mulmod(mload(0x920), mload(0x2f60), f_q)) - mstore(0x2fa0, addmod(1, sub(f_q, mload(0x2720)), f_q)) - mstore(0x2fc0, addmod(mload(0x2740), mload(0x2760), f_q)) - mstore(0x2fe0, addmod(mload(0x2fc0), mload(0x2780), f_q)) + mstore(0x2e00, mulmod(mload(0xb00), mload(0xae0), f_q)) + mstore(0x2e20, addmod(mload(0xac0), mload(0x2e00), f_q)) + mstore(0x2e40, addmod(mload(0x2e20), sub(f_q, mload(0xb20)), f_q)) + mstore(0x2e60, mulmod(mload(0x2e40), mload(0xb80), f_q)) + mstore(0x2e80, mulmod(mload(0x920), mload(0x2e60), f_q)) + mstore(0x2ea0, addmod(1, sub(f_q, mload(0xc40)), f_q)) + mstore(0x2ec0, mulmod(mload(0x2ea0), mload(0x2820), f_q)) + mstore(0x2ee0, addmod(mload(0x2e80), mload(0x2ec0), f_q)) + mstore(0x2f00, mulmod(mload(0x920), mload(0x2ee0), f_q)) + mstore(0x2f20, mulmod(mload(0xc40), mload(0xc40), f_q)) + mstore(0x2f40, addmod(mload(0x2f20), sub(f_q, mload(0xc40)), f_q)) + mstore(0x2f60, mulmod(mload(0x2f40), mload(0x2740), f_q)) + mstore(0x2f80, addmod(mload(0x2f00), mload(0x2f60), f_q)) + mstore(0x2fa0, mulmod(mload(0x920), mload(0x2f80), f_q)) + mstore(0x2fc0, addmod(1, sub(f_q, mload(0x2740)), f_q)) + mstore(0x2fe0, addmod(mload(0x2760), mload(0x2780), f_q)) mstore(0x3000, addmod(mload(0x2fe0), mload(0x27a0), f_q)) mstore(0x3020, addmod(mload(0x3000), mload(0x27c0), f_q)) mstore(0x3040, addmod(mload(0x3020), mload(0x27e0), f_q)) - mstore(0x3060, addmod(mload(0x2fa0), sub(f_q, mload(0x3040)), f_q)) - mstore(0x3080, mulmod(mload(0xbe0), mload(0x7a0), f_q)) - mstore(0x30a0, addmod(mload(0xb40), mload(0x3080), f_q)) - mstore(0x30c0, addmod(mload(0x30a0), mload(0x800), f_q)) - mstore(0x30e0, mulmod(mload(0xc00), mload(0x7a0), f_q)) - mstore(0x3100, addmod(mload(0xac0), mload(0x30e0), f_q)) - mstore(0x3120, addmod(mload(0x3100), mload(0x800), f_q)) - mstore(0x3140, mulmod(mload(0x3120), mload(0x30c0), f_q)) - mstore(0x3160, mulmod(mload(0xc20), mload(0x7a0), f_q)) - mstore(0x3180, addmod(mload(0x2dc0), mload(0x3160), f_q)) - mstore(0x31a0, addmod(mload(0x3180), mload(0x800), f_q)) - mstore(0x31c0, mulmod(mload(0x31a0), mload(0x3140), f_q)) - mstore(0x31e0, mulmod(mload(0x31c0), mload(0xc60), f_q)) - mstore(0x3200, mulmod(1, mload(0x7a0), f_q)) - mstore(0x3220, mulmod(mload(0xa80), mload(0x3200), f_q)) - mstore(0x3240, addmod(mload(0xb40), mload(0x3220), f_q)) - mstore(0x3260, addmod(mload(0x3240), mload(0x800), f_q)) - mstore( - 0x3280, + mstore(0x3060, addmod(mload(0x3040), mload(0x2800), f_q)) + mstore(0x3080, addmod(mload(0x2fc0), sub(f_q, mload(0x3060)), f_q)) + mstore(0x30a0, mulmod(mload(0xbe0), mload(0x7a0), f_q)) + mstore(0x30c0, addmod(mload(0xb40), mload(0x30a0), f_q)) + mstore(0x30e0, addmod(mload(0x30c0), mload(0x800), f_q)) + mstore(0x3100, mulmod(mload(0xc00), mload(0x7a0), f_q)) + mstore(0x3120, addmod(mload(0xac0), mload(0x3100), f_q)) + mstore(0x3140, addmod(mload(0x3120), mload(0x800), f_q)) + mstore(0x3160, mulmod(mload(0x3140), mload(0x30e0), f_q)) + mstore(0x3180, mulmod(mload(0xc20), mload(0x7a0), f_q)) + mstore(0x31a0, addmod(mload(0x2de0), mload(0x3180), f_q)) + mstore(0x31c0, addmod(mload(0x31a0), mload(0x800), f_q)) + mstore(0x31e0, mulmod(mload(0x31c0), mload(0x3160), f_q)) + mstore(0x3200, mulmod(mload(0x31e0), mload(0xc60), f_q)) + mstore(0x3220, mulmod(1, mload(0x7a0), f_q)) + mstore(0x3240, mulmod(mload(0xa80), mload(0x3220), f_q)) + mstore(0x3260, addmod(mload(0xb40), mload(0x3240), f_q)) + mstore(0x3280, addmod(mload(0x3260), mload(0x800), f_q)) + mstore( + 0x32a0, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x7a0), f_q) ) - mstore(0x32a0, mulmod(mload(0xa80), mload(0x3280), f_q)) - mstore(0x32c0, addmod(mload(0xac0), mload(0x32a0), f_q)) - mstore(0x32e0, addmod(mload(0x32c0), mload(0x800), f_q)) - mstore(0x3300, mulmod(mload(0x32e0), mload(0x3260), f_q)) + mstore(0x32c0, mulmod(mload(0xa80), mload(0x32a0), f_q)) + mstore(0x32e0, addmod(mload(0xac0), mload(0x32c0), f_q)) + mstore(0x3300, addmod(mload(0x32e0), mload(0x800), f_q)) + mstore(0x3320, mulmod(mload(0x3300), mload(0x3280), f_q)) mstore( - 0x3320, + 0x3340, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x7a0), f_q) ) - mstore(0x3340, mulmod(mload(0xa80), mload(0x3320), f_q)) - mstore(0x3360, addmod(mload(0x2dc0), mload(0x3340), f_q)) - mstore(0x3380, addmod(mload(0x3360), mload(0x800), f_q)) - mstore(0x33a0, mulmod(mload(0x3380), mload(0x3300), f_q)) - mstore(0x33c0, mulmod(mload(0x33a0), mload(0xc40), f_q)) - mstore(0x33e0, addmod(mload(0x31e0), sub(f_q, mload(0x33c0)), f_q)) - mstore(0x3400, mulmod(mload(0x33e0), mload(0x3060), f_q)) - mstore(0x3420, addmod(mload(0x2f80), mload(0x3400), f_q)) - mstore(0x3440, mulmod(mload(0x920), mload(0x3420), f_q)) - mstore(0x3460, addmod(1, sub(f_q, mload(0xc80)), f_q)) - mstore(0x3480, mulmod(mload(0x3460), mload(0x2800), f_q)) - mstore(0x34a0, addmod(mload(0x3440), mload(0x3480), f_q)) - mstore(0x34c0, mulmod(mload(0x920), mload(0x34a0), f_q)) - mstore(0x34e0, mulmod(mload(0xc80), mload(0xc80), f_q)) - mstore(0x3500, addmod(mload(0x34e0), sub(f_q, mload(0xc80)), f_q)) - mstore(0x3520, mulmod(mload(0x3500), mload(0x2720), f_q)) - mstore(0x3540, addmod(mload(0x34c0), mload(0x3520), f_q)) - mstore(0x3560, mulmod(mload(0x920), mload(0x3540), f_q)) - mstore(0x3580, addmod(mload(0xcc0), mload(0x7a0), f_q)) - mstore(0x35a0, mulmod(mload(0x3580), mload(0xca0), f_q)) - mstore(0x35c0, addmod(mload(0xd00), mload(0x800), f_q)) - mstore(0x35e0, mulmod(mload(0x35c0), mload(0x35a0), f_q)) - mstore(0x3600, mulmod(mload(0xac0), mload(0xba0), f_q)) - mstore(0x3620, addmod(mload(0x3600), mload(0x7a0), f_q)) - mstore(0x3640, mulmod(mload(0x3620), mload(0xc80), f_q)) - mstore(0x3660, addmod(mload(0xb60), mload(0x800), f_q)) - mstore(0x3680, mulmod(mload(0x3660), mload(0x3640), f_q)) - mstore(0x36a0, addmod(mload(0x35e0), sub(f_q, mload(0x3680)), f_q)) - mstore(0x36c0, mulmod(mload(0x36a0), mload(0x3060), f_q)) - mstore(0x36e0, addmod(mload(0x3560), mload(0x36c0), f_q)) - mstore(0x3700, mulmod(mload(0x920), mload(0x36e0), f_q)) - mstore(0x3720, addmod(mload(0xcc0), sub(f_q, mload(0xd00)), f_q)) - mstore(0x3740, mulmod(mload(0x3720), mload(0x2800), f_q)) - mstore(0x3760, addmod(mload(0x3700), mload(0x3740), f_q)) - mstore(0x3780, mulmod(mload(0x920), mload(0x3760), f_q)) - mstore(0x37a0, mulmod(mload(0x3720), mload(0x3060), f_q)) - mstore(0x37c0, addmod(mload(0xcc0), sub(f_q, mload(0xce0)), f_q)) - mstore(0x37e0, mulmod(mload(0x37c0), mload(0x37a0), f_q)) - mstore(0x3800, addmod(mload(0x3780), mload(0x37e0), f_q)) - mstore(0x3820, mulmod(mload(0x1200), mload(0x1200), f_q)) - mstore(0x3840, mulmod(mload(0x3820), mload(0x1200), f_q)) - mstore(0x3860, mulmod(mload(0x3840), mload(0x1200), f_q)) - mstore(0x3880, mulmod(1, mload(0x1200), f_q)) - mstore(0x38a0, mulmod(1, mload(0x3820), f_q)) + mstore(0x3360, mulmod(mload(0xa80), mload(0x3340), f_q)) + mstore(0x3380, addmod(mload(0x2de0), mload(0x3360), f_q)) + mstore(0x33a0, addmod(mload(0x3380), mload(0x800), f_q)) + mstore(0x33c0, mulmod(mload(0x33a0), mload(0x3320), f_q)) + mstore(0x33e0, mulmod(mload(0x33c0), mload(0xc40), f_q)) + mstore(0x3400, addmod(mload(0x3200), sub(f_q, mload(0x33e0)), f_q)) + mstore(0x3420, mulmod(mload(0x3400), mload(0x3080), f_q)) + mstore(0x3440, addmod(mload(0x2fa0), mload(0x3420), f_q)) + mstore(0x3460, mulmod(mload(0x920), mload(0x3440), f_q)) + mstore(0x3480, addmod(1, sub(f_q, mload(0xc80)), f_q)) + mstore(0x34a0, mulmod(mload(0x3480), mload(0x2820), f_q)) + mstore(0x34c0, addmod(mload(0x3460), mload(0x34a0), f_q)) + mstore(0x34e0, mulmod(mload(0x920), mload(0x34c0), f_q)) + mstore(0x3500, mulmod(mload(0xc80), mload(0xc80), f_q)) + mstore(0x3520, addmod(mload(0x3500), sub(f_q, mload(0xc80)), f_q)) + mstore(0x3540, mulmod(mload(0x3520), mload(0x2740), f_q)) + mstore(0x3560, addmod(mload(0x34e0), mload(0x3540), f_q)) + mstore(0x3580, mulmod(mload(0x920), mload(0x3560), f_q)) + mstore(0x35a0, addmod(mload(0xcc0), mload(0x7a0), f_q)) + mstore(0x35c0, mulmod(mload(0x35a0), mload(0xca0), f_q)) + mstore(0x35e0, addmod(mload(0xd00), mload(0x800), f_q)) + mstore(0x3600, mulmod(mload(0x35e0), mload(0x35c0), f_q)) + mstore(0x3620, mulmod(mload(0xac0), mload(0xba0), f_q)) + mstore(0x3640, addmod(mload(0x3620), mload(0x7a0), f_q)) + mstore(0x3660, mulmod(mload(0x3640), mload(0xc80), f_q)) + mstore(0x3680, addmod(mload(0xb60), mload(0x800), f_q)) + mstore(0x36a0, mulmod(mload(0x3680), mload(0x3660), f_q)) + mstore(0x36c0, addmod(mload(0x3600), sub(f_q, mload(0x36a0)), f_q)) + mstore(0x36e0, mulmod(mload(0x36c0), mload(0x3080), f_q)) + mstore(0x3700, addmod(mload(0x3580), mload(0x36e0), f_q)) + mstore(0x3720, mulmod(mload(0x920), mload(0x3700), f_q)) + mstore(0x3740, addmod(mload(0xcc0), sub(f_q, mload(0xd00)), f_q)) + mstore(0x3760, mulmod(mload(0x3740), mload(0x2820), f_q)) + mstore(0x3780, addmod(mload(0x3720), mload(0x3760), f_q)) + mstore(0x37a0, mulmod(mload(0x920), mload(0x3780), f_q)) + mstore(0x37c0, mulmod(mload(0x3740), mload(0x3080), f_q)) + mstore(0x37e0, addmod(mload(0xcc0), sub(f_q, mload(0xce0)), f_q)) + mstore(0x3800, mulmod(mload(0x37e0), mload(0x37c0), f_q)) + mstore(0x3820, addmod(mload(0x37a0), mload(0x3800), f_q)) + mstore(0x3840, mulmod(mload(0x1220), mload(0x1220), f_q)) + mstore(0x3860, mulmod(mload(0x3840), mload(0x1220), f_q)) + mstore(0x3880, mulmod(mload(0x3860), mload(0x1220), f_q)) + mstore(0x38a0, mulmod(1, mload(0x1220), f_q)) mstore(0x38c0, mulmod(1, mload(0x3840), f_q)) - mstore(0x38e0, mulmod(mload(0x3800), mload(0x1220), f_q)) - mstore(0x3900, mulmod(mload(0xf40), mload(0xa80), f_q)) - mstore(0x3920, mulmod(mload(0x3900), mload(0xa80), f_q)) + mstore(0x38e0, mulmod(1, mload(0x3860), f_q)) + mstore(0x3900, mulmod(mload(0x3820), mload(0x1240), f_q)) + mstore(0x3920, mulmod(mload(0xf40), mload(0xa80), f_q)) + mstore(0x3940, mulmod(mload(0x3920), mload(0xa80), f_q)) mstore( - 0x3940, - mulmod(mload(0xa80), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q) + 0x3960, + mulmod(mload(0xa80), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q) ) - mstore(0x3960, addmod(mload(0xe40), sub(f_q, mload(0x3940)), f_q)) - mstore(0x3980, mulmod(mload(0xa80), 1, f_q)) - mstore(0x39a0, addmod(mload(0xe40), sub(f_q, mload(0x3980)), f_q)) + mstore(0x3980, addmod(mload(0xe40), sub(f_q, mload(0x3960)), f_q)) + mstore(0x39a0, mulmod(mload(0xa80), 1, f_q)) + mstore(0x39c0, addmod(mload(0xe40), sub(f_q, mload(0x39a0)), f_q)) mstore( - 0x39c0, - mulmod(mload(0xa80), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) + 0x39e0, + mulmod(mload(0xa80), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q) ) - mstore(0x39e0, addmod(mload(0xe40), sub(f_q, mload(0x39c0)), f_q)) + mstore(0x3a00, addmod(mload(0xe40), sub(f_q, mload(0x39e0)), f_q)) mstore( - 0x3a00, - mulmod(mload(0xa80), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q) + 0x3a20, + mulmod(mload(0xa80), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) ) - mstore(0x3a20, addmod(mload(0xe40), sub(f_q, mload(0x3a00)), f_q)) + mstore(0x3a40, addmod(mload(0xe40), sub(f_q, mload(0x3a20)), f_q)) mstore( - 0x3a40, - mulmod(mload(0xa80), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q) + 0x3a60, + mulmod(mload(0xa80), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q) ) - mstore(0x3a60, addmod(mload(0xe40), sub(f_q, mload(0x3a40)), f_q)) + mstore(0x3a80, addmod(mload(0xe40), sub(f_q, mload(0x3a60)), f_q)) mstore( - 0x3a80, - mulmod( - 13213688729882003894512633350385593288217014177373218494356903340348818451480, mload(0x3900), f_q - ) + 0x3aa0, + mulmod(6616149745577394522356295102346368305374051634342887004165528916468992151333, mload(0x3920), f_q) ) - mstore(0x3aa0, mulmod(mload(0x3a80), 1, f_q)) + mstore(0x3ac0, mulmod(mload(0x3aa0), 1, f_q)) { - let result := mulmod(mload(0xe40), mload(0x3a80), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3aa0)), f_q), result, f_q) - mstore(15040, result) + let result := mulmod(mload(0xe40), mload(0x3aa0), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ac0)), f_q), result, f_q) + mstore(15072, result) } mstore( - 0x3ae0, - mulmod(8207090019724696496350398458716998472718344609680392612601596849934418295470, mload(0x3900), f_q) + 0x3b00, + mulmod(530501691302793820034524283154921640443166880847115433758691660016816186416, mload(0x3920), f_q) ) mstore( - 0x3b00, - mulmod(mload(0x3ae0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) + 0x3b20, + mulmod( + mload(0x3b00), + 11451405578697956743456240853980216273390554734748796433026540431386972584651, + f_q + ) ) { - let result := mulmod(mload(0xe40), mload(0x3ae0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b00)), f_q), result, f_q) - mstore(15136, result) + let result := mulmod(mload(0xe40), mload(0x3b00), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b20)), f_q), result, f_q) + mstore(15168, result) } mstore( - 0x3b40, - mulmod(7391709068497399131897422873231908718558236401035363928063603272120120747483, mload(0x3900), f_q) + 0x3b60, + mulmod(6735468303947967792722299167169712601265763928443086612877978228369959138708, mload(0x3920), f_q) ) mstore( - 0x3b60, - mulmod( - mload(0x3b40), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q - ) + 0x3b80, + mulmod(mload(0x3b60), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) ) { - let result := mulmod(mload(0xe40), mload(0x3b40), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b60)), f_q), result, f_q) - mstore(15232, result) + let result := mulmod(mload(0xe40), mload(0x3b60), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b80)), f_q), result, f_q) + mstore(15264, result) } mstore( - 0x3ba0, + 0x3bc0, mulmod( - 19036273796805830823244991598792794567595348772040298280440552631112242221017, mload(0x3900), f_q + 21558793644302942916864965630979640748886316167261336210841195936026980690666, + mload(0x3920), + f_q ) ) mstore( - 0x3bc0, - mulmod(mload(0x3ba0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q) + 0x3be0, + mulmod( + mload(0x3bc0), + 21490807004895109926141140246143262403290679459142140821740925192625185504522, + f_q + ) ) { - let result := mulmod(mload(0xe40), mload(0x3ba0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3bc0)), f_q), result, f_q) - mstore(15328, result) + let result := mulmod(mload(0xe40), mload(0x3bc0), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3be0)), f_q), result, f_q) + mstore(15360, result) } - mstore(0x3c00, mulmod(1, mload(0x39a0), f_q)) - mstore(0x3c20, mulmod(mload(0x3c00), mload(0x39e0), f_q)) - mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3a20), f_q)) - mstore(0x3c60, mulmod(mload(0x3c40), mload(0x3a60), f_q)) + mstore(0x3c20, mulmod(1, mload(0x39c0), f_q)) + mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3a00), f_q)) + mstore(0x3c60, mulmod(mload(0x3c40), mload(0x3a40), f_q)) + mstore(0x3c80, mulmod(mload(0x3c60), mload(0x3a80), f_q)) mstore( - 0x3c80, - mulmod(13513867906530865119835332133273263211836799082674232843258448413103731898271, mload(0xa80), f_q) + 0x3ca0, + mulmod(10436837293141318478790164891277058815157809665667237910671663755188835910967, mload(0xa80), f_q) ) - mstore(0x3ca0, mulmod(mload(0x3c80), 1, f_q)) + mstore(0x3cc0, mulmod(mload(0x3ca0), 1, f_q)) { - let result := mulmod(mload(0xe40), mload(0x3c80), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ca0)), f_q), result, f_q) - mstore(15552, result) + let result := mulmod(mload(0xe40), mload(0x3ca0), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3cc0)), f_q), result, f_q) + mstore(15584, result) } mstore( - 0x3ce0, - mulmod(8374374965308410102411073611984011876711565317741801500439755773472076597346, mload(0xa80), f_q) + 0x3d00, + mulmod(11451405578697956743456240853980216273390554734748796433026540431386972584650, mload(0xa80), f_q) ) mstore( - 0x3d00, - mulmod(mload(0x3ce0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) + 0x3d20, + mulmod( + mload(0x3d00), + 11451405578697956743456240853980216273390554734748796433026540431386972584651, + f_q + ) ) { - let result := mulmod(mload(0xe40), mload(0x3ce0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d00)), f_q), result, f_q) - mstore(15648, result) + let result := mulmod(mload(0xe40), mload(0x3d00), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d20)), f_q), result, f_q) + mstore(15680, result) } mstore( - 0x3d40, - mulmod(12146688980418810893951125255607130521645347193942732958664170801695864621271, mload(0xa80), f_q) + 0x3d60, + mulmod(4558794634599160729665540001169218674296628713450539706539395399156027320108, mload(0xa80), f_q) ) - mstore(0x3d60, mulmod(mload(0x3d40), 1, f_q)) + mstore(0x3d80, mulmod(mload(0x3d60), 1, f_q)) { - let result := mulmod(mload(0xe40), mload(0x3d40), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d60)), f_q), result, f_q) - mstore(15744, result) + let result := mulmod(mload(0xe40), mload(0x3d60), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d80)), f_q), result, f_q) + mstore(15776, result) } mstore( - 0x3da0, - mulmod(9741553891420464328295280489650144566903017206473301385034033384879943874346, mload(0xa80), f_q) + 0x3dc0, + mulmod(17329448237240114492580865744088056414251735686965494637158808787419781175509, mload(0xa80), f_q) ) mstore( - 0x3dc0, - mulmod(mload(0x3da0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q) + 0x3de0, + mulmod( + mload(0x3dc0), + 17329448237240114492580865744088056414251735686965494637158808787419781175510, + f_q + ) ) { - let result := mulmod(mload(0xe40), mload(0x3da0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3dc0)), f_q), result, f_q) - mstore(15840, result) + let result := mulmod(mload(0xe40), mload(0x3dc0), f_q) + result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3de0)), f_q), result, f_q) + mstore(15872, result) } - mstore(0x3e00, mulmod(mload(0x3c00), mload(0x3960), f_q)) + mstore(0x3e20, mulmod(mload(0x3c20), mload(0x3980), f_q)) { let result := mulmod(mload(0xe40), 1, f_q) - result := - addmod( - mulmod( - mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q - ), - result, + result := addmod( + mulmod( + mload(0xa80), + 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q - ) - mstore(15904, result) + ), + result, + f_q + ) + mstore(15936, result) } { - let prod := mload(0x3ac0) + let prod := mload(0x3ae0) - prod := mulmod(mload(0x3b20), prod, f_q) - mstore(0x3e40, prod) - - prod := mulmod(mload(0x3b80), prod, f_q) + prod := mulmod(mload(0x3b40), prod, f_q) mstore(0x3e60, prod) - prod := mulmod(mload(0x3be0), prod, f_q) + prod := mulmod(mload(0x3ba0), prod, f_q) mstore(0x3e80, prod) - prod := mulmod(mload(0x3cc0), prod, f_q) + prod := mulmod(mload(0x3c00), prod, f_q) mstore(0x3ea0, prod) - prod := mulmod(mload(0x3d20), prod, f_q) + prod := mulmod(mload(0x3ce0), prod, f_q) mstore(0x3ec0, prod) - prod := mulmod(mload(0x3c20), prod, f_q) + prod := mulmod(mload(0x3d40), prod, f_q) mstore(0x3ee0, prod) - prod := mulmod(mload(0x3d80), prod, f_q) + prod := mulmod(mload(0x3c40), prod, f_q) mstore(0x3f00, prod) - prod := mulmod(mload(0x3de0), prod, f_q) + prod := mulmod(mload(0x3da0), prod, f_q) mstore(0x3f20, prod) prod := mulmod(mload(0x3e00), prod, f_q) @@ -1529,22 +1606,29 @@ contract Halo2Verifier { prod := mulmod(mload(0x3e20), prod, f_q) mstore(0x3f60, prod) - prod := mulmod(mload(0x3c00), prod, f_q) + prod := mulmod(mload(0x3e40), prod, f_q) mstore(0x3f80, prod) + + prod := mulmod(mload(0x3c20), prod, f_q) + mstore(0x3fa0, prod) } - mstore(0x3fc0, 32) mstore(0x3fe0, 32) mstore(0x4000, 32) - mstore(0x4020, mload(0x3f80)) - mstore(0x4040, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x4060, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x3fc0, 0xc0, 0x3fa0, 0x20), 1), success) + mstore(0x4020, 32) + mstore(0x4040, mload(0x3fa0)) + mstore(0x4060, 21888242871839275222246405745257275088548364400416034343698204186575808495615) + mstore(0x4080, 21888242871839275222246405745257275088548364400416034343698204186575808495617) + success := and(eq(staticcall(gas(), 0x5, 0x3fe0, 0xc0, 0x3fc0, 0x20), 1), success) { - let inv := mload(0x3fa0) + let inv := mload(0x3fc0) let v - v := mload(0x3c00) - mstore(15360, mulmod(mload(0x3f60), inv, f_q)) + v := mload(0x3c20) + mstore(15392, mulmod(mload(0x3f80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3e40) + mstore(15936, mulmod(mload(0x3f60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x3e20) @@ -1555,104 +1639,99 @@ contract Halo2Verifier { mstore(15872, mulmod(mload(0x3f20), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3de0) - mstore(15840, mulmod(mload(0x3f00), inv, f_q)) + v := mload(0x3da0) + mstore(15776, mulmod(mload(0x3f00), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3d80) - mstore(15744, mulmod(mload(0x3ee0), inv, f_q)) + v := mload(0x3c40) + mstore(15424, mulmod(mload(0x3ee0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3c20) - mstore(15392, mulmod(mload(0x3ec0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3d20) - mstore(15648, mulmod(mload(0x3ea0), inv, f_q)) + v := mload(0x3d40) + mstore(15680, mulmod(mload(0x3ec0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3cc0) - mstore(15552, mulmod(mload(0x3e80), inv, f_q)) + v := mload(0x3ce0) + mstore(15584, mulmod(mload(0x3ea0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3be0) - mstore(15328, mulmod(mload(0x3e60), inv, f_q)) + v := mload(0x3c00) + mstore(15360, mulmod(mload(0x3e80), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3b80) - mstore(15232, mulmod(mload(0x3e40), inv, f_q)) + v := mload(0x3ba0) + mstore(15264, mulmod(mload(0x3e60), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3b20) - mstore(15136, mulmod(mload(0x3ac0), inv, f_q)) + v := mload(0x3b40) + mstore(15168, mulmod(mload(0x3ae0), inv, f_q)) inv := mulmod(v, inv, f_q) - mstore(0x3ac0, inv) + mstore(0x3ae0, inv) } { - let result := mload(0x3ac0) - result := addmod(mload(0x3b20), result, f_q) - result := addmod(mload(0x3b80), result, f_q) - result := addmod(mload(0x3be0), result, f_q) - mstore(16512, result) + let result := mload(0x3ae0) + result := addmod(mload(0x3b40), result, f_q) + result := addmod(mload(0x3ba0), result, f_q) + result := addmod(mload(0x3c00), result, f_q) + mstore(16544, result) } - mstore(0x40a0, mulmod(mload(0x3c60), mload(0x3c20), f_q)) + mstore(0x40c0, mulmod(mload(0x3c80), mload(0x3c40), f_q)) { - let result := mload(0x3cc0) - result := addmod(mload(0x3d20), result, f_q) - mstore(16576, result) + let result := mload(0x3ce0) + result := addmod(mload(0x3d40), result, f_q) + mstore(16608, result) } - mstore(0x40e0, mulmod(mload(0x3c60), mload(0x3e00), f_q)) + mstore(0x4100, mulmod(mload(0x3c80), mload(0x3e20), f_q)) { - let result := mload(0x3d80) - result := addmod(mload(0x3de0), result, f_q) - mstore(16640, result) + let result := mload(0x3da0) + result := addmod(mload(0x3e00), result, f_q) + mstore(16672, result) } - mstore(0x4120, mulmod(mload(0x3c60), mload(0x3c00), f_q)) + mstore(0x4140, mulmod(mload(0x3c80), mload(0x3c20), f_q)) { - let result := mload(0x3e20) - mstore(16704, result) + let result := mload(0x3e40) + mstore(16736, result) } { - let prod := mload(0x4080) - - prod := mulmod(mload(0x40c0), prod, f_q) - mstore(0x4160, prod) + let prod := mload(0x40a0) - prod := mulmod(mload(0x4100), prod, f_q) + prod := mulmod(mload(0x40e0), prod, f_q) mstore(0x4180, prod) - prod := mulmod(mload(0x4140), prod, f_q) + prod := mulmod(mload(0x4120), prod, f_q) mstore(0x41a0, prod) + + prod := mulmod(mload(0x4160), prod, f_q) + mstore(0x41c0, prod) } - mstore(0x41e0, 32) mstore(0x4200, 32) mstore(0x4220, 32) - mstore(0x4240, mload(0x41a0)) - mstore(0x4260, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x4280, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x41e0, 0xc0, 0x41c0, 0x20), 1), success) + mstore(0x4240, 32) + mstore(0x4260, mload(0x41c0)) + mstore(0x4280, 21888242871839275222246405745257275088548364400416034343698204186575808495615) + mstore(0x42a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) + success := and(eq(staticcall(gas(), 0x5, 0x4200, 0xc0, 0x41e0, 0x20), 1), success) { - let inv := mload(0x41c0) + let inv := mload(0x41e0) let v - v := mload(0x4140) - mstore(16704, mulmod(mload(0x4180), inv, f_q)) + v := mload(0x4160) + mstore(16736, mulmod(mload(0x41a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x4100) - mstore(16640, mulmod(mload(0x4160), inv, f_q)) + v := mload(0x4120) + mstore(16672, mulmod(mload(0x4180), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x40c0) - mstore(16576, mulmod(mload(0x4080), inv, f_q)) + v := mload(0x40e0) + mstore(16608, mulmod(mload(0x40a0), inv, f_q)) inv := mulmod(v, inv, f_q) - mstore(0x4080, inv) + mstore(0x40a0, inv) } - mstore(0x42a0, mulmod(mload(0x40a0), mload(0x40c0), f_q)) - mstore(0x42c0, mulmod(mload(0x40e0), mload(0x4100), f_q)) - mstore(0x42e0, mulmod(mload(0x4120), mload(0x4140), f_q)) - mstore(0x4300, mulmod(mload(0xd40), mload(0xd40), f_q)) - mstore(0x4320, mulmod(mload(0x4300), mload(0xd40), f_q)) + mstore(0x42c0, mulmod(mload(0x40c0), mload(0x40e0), f_q)) + mstore(0x42e0, mulmod(mload(0x4100), mload(0x4120), f_q)) + mstore(0x4300, mulmod(mload(0x4140), mload(0x4160), f_q)) + mstore(0x4320, mulmod(mload(0xd40), mload(0xd40), f_q)) mstore(0x4340, mulmod(mload(0x4320), mload(0xd40), f_q)) mstore(0x4360, mulmod(mload(0x4340), mload(0xd40), f_q)) mstore(0x4380, mulmod(mload(0x4360), mload(0xd40), f_q)) @@ -1660,371 +1739,372 @@ contract Halo2Verifier { mstore(0x43c0, mulmod(mload(0x43a0), mload(0xd40), f_q)) mstore(0x43e0, mulmod(mload(0x43c0), mload(0xd40), f_q)) mstore(0x4400, mulmod(mload(0x43e0), mload(0xd40), f_q)) - mstore(0x4420, mulmod(mload(0xda0), mload(0xda0), f_q)) - mstore(0x4440, mulmod(mload(0x4420), mload(0xda0), f_q)) + mstore(0x4420, mulmod(mload(0x4400), mload(0xd40), f_q)) + mstore(0x4440, mulmod(mload(0xda0), mload(0xda0), f_q)) mstore(0x4460, mulmod(mload(0x4440), mload(0xda0), f_q)) + mstore(0x4480, mulmod(mload(0x4460), mload(0xda0), f_q)) { - let result := mulmod(mload(0xac0), mload(0x3ac0), f_q) - result := addmod(mulmod(mload(0xae0), mload(0x3b20), f_q), result, f_q) - result := addmod(mulmod(mload(0xb00), mload(0x3b80), f_q), result, f_q) - result := addmod(mulmod(mload(0xb20), mload(0x3be0), f_q), result, f_q) - mstore(17536, result) + let result := mulmod(mload(0xac0), mload(0x3ae0), f_q) + result := addmod(mulmod(mload(0xae0), mload(0x3b40), f_q), result, f_q) + result := addmod(mulmod(mload(0xb00), mload(0x3ba0), f_q), result, f_q) + result := addmod(mulmod(mload(0xb20), mload(0x3c00), f_q), result, f_q) + mstore(17568, result) } - mstore(0x44a0, mulmod(mload(0x4480), mload(0x4080), f_q)) - mstore(0x44c0, mulmod(sub(f_q, mload(0x44a0)), 1, f_q)) - mstore(0x44e0, mulmod(mload(0x44c0), 1, f_q)) - mstore(0x4500, mulmod(1, mload(0x40a0), f_q)) + mstore(0x44c0, mulmod(mload(0x44a0), mload(0x40a0), f_q)) + mstore(0x44e0, mulmod(sub(f_q, mload(0x44c0)), 1, f_q)) + mstore(0x4500, mulmod(mload(0x44e0), 1, f_q)) + mstore(0x4520, mulmod(1, mload(0x40c0), f_q)) { - let result := mulmod(mload(0xc40), mload(0x3cc0), f_q) - result := addmod(mulmod(mload(0xc60), mload(0x3d20), f_q), result, f_q) - mstore(17696, result) + let result := mulmod(mload(0xc40), mload(0x3ce0), f_q) + result := addmod(mulmod(mload(0xc60), mload(0x3d40), f_q), result, f_q) + mstore(17728, result) } - mstore(0x4540, mulmod(mload(0x4520), mload(0x42a0), f_q)) - mstore(0x4560, mulmod(sub(f_q, mload(0x4540)), 1, f_q)) - mstore(0x4580, mulmod(mload(0x4500), 1, f_q)) + mstore(0x4560, mulmod(mload(0x4540), mload(0x42c0), f_q)) + mstore(0x4580, mulmod(sub(f_q, mload(0x4560)), 1, f_q)) + mstore(0x45a0, mulmod(mload(0x4520), 1, f_q)) { - let result := mulmod(mload(0xc80), mload(0x3cc0), f_q) - result := addmod(mulmod(mload(0xca0), mload(0x3d20), f_q), result, f_q) - mstore(17824, result) + let result := mulmod(mload(0xc80), mload(0x3ce0), f_q) + result := addmod(mulmod(mload(0xca0), mload(0x3d40), f_q), result, f_q) + mstore(17856, result) } - mstore(0x45c0, mulmod(mload(0x45a0), mload(0x42a0), f_q)) - mstore(0x45e0, mulmod(sub(f_q, mload(0x45c0)), mload(0xd40), f_q)) - mstore(0x4600, mulmod(mload(0x4500), mload(0xd40), f_q)) - mstore(0x4620, addmod(mload(0x4560), mload(0x45e0), f_q)) - mstore(0x4640, mulmod(mload(0x4620), mload(0xda0), f_q)) - mstore(0x4660, mulmod(mload(0x4580), mload(0xda0), f_q)) - mstore(0x4680, mulmod(mload(0x4600), mload(0xda0), f_q)) - mstore(0x46a0, addmod(mload(0x44e0), mload(0x4640), f_q)) - mstore(0x46c0, mulmod(1, mload(0x40e0), f_q)) + mstore(0x45e0, mulmod(mload(0x45c0), mload(0x42c0), f_q)) + mstore(0x4600, mulmod(sub(f_q, mload(0x45e0)), mload(0xd40), f_q)) + mstore(0x4620, mulmod(mload(0x4520), mload(0xd40), f_q)) + mstore(0x4640, addmod(mload(0x4580), mload(0x4600), f_q)) + mstore(0x4660, mulmod(mload(0x4640), mload(0xda0), f_q)) + mstore(0x4680, mulmod(mload(0x45a0), mload(0xda0), f_q)) + mstore(0x46a0, mulmod(mload(0x4620), mload(0xda0), f_q)) + mstore(0x46c0, addmod(mload(0x4500), mload(0x4660), f_q)) + mstore(0x46e0, mulmod(1, mload(0x4100), f_q)) { - let result := mulmod(mload(0xcc0), mload(0x3d80), f_q) - result := addmod(mulmod(mload(0xce0), mload(0x3de0), f_q), result, f_q) - mstore(18144, result) + let result := mulmod(mload(0xcc0), mload(0x3da0), f_q) + result := addmod(mulmod(mload(0xce0), mload(0x3e00), f_q), result, f_q) + mstore(18176, result) } - mstore(0x4700, mulmod(mload(0x46e0), mload(0x42c0), f_q)) - mstore(0x4720, mulmod(sub(f_q, mload(0x4700)), 1, f_q)) - mstore(0x4740, mulmod(mload(0x46c0), 1, f_q)) - mstore(0x4760, mulmod(mload(0x4720), mload(0x4420), f_q)) - mstore(0x4780, mulmod(mload(0x4740), mload(0x4420), f_q)) - mstore(0x47a0, addmod(mload(0x46a0), mload(0x4760), f_q)) - mstore(0x47c0, mulmod(1, mload(0x4120), f_q)) + mstore(0x4720, mulmod(mload(0x4700), mload(0x42e0), f_q)) + mstore(0x4740, mulmod(sub(f_q, mload(0x4720)), 1, f_q)) + mstore(0x4760, mulmod(mload(0x46e0), 1, f_q)) + mstore(0x4780, mulmod(mload(0x4740), mload(0x4440), f_q)) + mstore(0x47a0, mulmod(mload(0x4760), mload(0x4440), f_q)) + mstore(0x47c0, addmod(mload(0x46c0), mload(0x4780), f_q)) + mstore(0x47e0, mulmod(1, mload(0x4140), f_q)) { - let result := mulmod(mload(0xd00), mload(0x3e20), f_q) - mstore(18400, result) + let result := mulmod(mload(0xd00), mload(0x3e40), f_q) + mstore(18432, result) } - mstore(0x4800, mulmod(mload(0x47e0), mload(0x42e0), f_q)) - mstore(0x4820, mulmod(sub(f_q, mload(0x4800)), 1, f_q)) - mstore(0x4840, mulmod(mload(0x47c0), 1, f_q)) + mstore(0x4820, mulmod(mload(0x4800), mload(0x4300), f_q)) + mstore(0x4840, mulmod(sub(f_q, mload(0x4820)), 1, f_q)) + mstore(0x4860, mulmod(mload(0x47e0), 1, f_q)) { - let result := mulmod(mload(0xb40), mload(0x3e20), f_q) - mstore(18528, result) + let result := mulmod(mload(0xb40), mload(0x3e40), f_q) + mstore(18560, result) } - mstore(0x4880, mulmod(mload(0x4860), mload(0x42e0), f_q)) - mstore(0x48a0, mulmod(sub(f_q, mload(0x4880)), mload(0xd40), f_q)) - mstore(0x48c0, mulmod(mload(0x47c0), mload(0xd40), f_q)) - mstore(0x48e0, addmod(mload(0x4820), mload(0x48a0), f_q)) + mstore(0x48a0, mulmod(mload(0x4880), mload(0x4300), f_q)) + mstore(0x48c0, mulmod(sub(f_q, mload(0x48a0)), mload(0xd40), f_q)) + mstore(0x48e0, mulmod(mload(0x47e0), mload(0xd40), f_q)) + mstore(0x4900, addmod(mload(0x4840), mload(0x48c0), f_q)) { - let result := mulmod(mload(0xb60), mload(0x3e20), f_q) - mstore(18688, result) + let result := mulmod(mload(0xb60), mload(0x3e40), f_q) + mstore(18720, result) } - mstore(0x4920, mulmod(mload(0x4900), mload(0x42e0), f_q)) - mstore(0x4940, mulmod(sub(f_q, mload(0x4920)), mload(0x4300), f_q)) - mstore(0x4960, mulmod(mload(0x47c0), mload(0x4300), f_q)) - mstore(0x4980, addmod(mload(0x48e0), mload(0x4940), f_q)) + mstore(0x4940, mulmod(mload(0x4920), mload(0x4300), f_q)) + mstore(0x4960, mulmod(sub(f_q, mload(0x4940)), mload(0x4320), f_q)) + mstore(0x4980, mulmod(mload(0x47e0), mload(0x4320), f_q)) + mstore(0x49a0, addmod(mload(0x4900), mload(0x4960), f_q)) { - let result := mulmod(mload(0xb80), mload(0x3e20), f_q) - mstore(18848, result) + let result := mulmod(mload(0xb80), mload(0x3e40), f_q) + mstore(18880, result) } - mstore(0x49c0, mulmod(mload(0x49a0), mload(0x42e0), f_q)) - mstore(0x49e0, mulmod(sub(f_q, mload(0x49c0)), mload(0x4320), f_q)) - mstore(0x4a00, mulmod(mload(0x47c0), mload(0x4320), f_q)) - mstore(0x4a20, addmod(mload(0x4980), mload(0x49e0), f_q)) + mstore(0x49e0, mulmod(mload(0x49c0), mload(0x4300), f_q)) + mstore(0x4a00, mulmod(sub(f_q, mload(0x49e0)), mload(0x4340), f_q)) + mstore(0x4a20, mulmod(mload(0x47e0), mload(0x4340), f_q)) + mstore(0x4a40, addmod(mload(0x49a0), mload(0x4a00), f_q)) { - let result := mulmod(mload(0xba0), mload(0x3e20), f_q) - mstore(19008, result) + let result := mulmod(mload(0xba0), mload(0x3e40), f_q) + mstore(19040, result) } - mstore(0x4a60, mulmod(mload(0x4a40), mload(0x42e0), f_q)) - mstore(0x4a80, mulmod(sub(f_q, mload(0x4a60)), mload(0x4340), f_q)) - mstore(0x4aa0, mulmod(mload(0x47c0), mload(0x4340), f_q)) - mstore(0x4ac0, addmod(mload(0x4a20), mload(0x4a80), f_q)) + mstore(0x4a80, mulmod(mload(0x4a60), mload(0x4300), f_q)) + mstore(0x4aa0, mulmod(sub(f_q, mload(0x4a80)), mload(0x4360), f_q)) + mstore(0x4ac0, mulmod(mload(0x47e0), mload(0x4360), f_q)) + mstore(0x4ae0, addmod(mload(0x4a40), mload(0x4aa0), f_q)) { - let result := mulmod(mload(0xbe0), mload(0x3e20), f_q) - mstore(19168, result) + let result := mulmod(mload(0xbe0), mload(0x3e40), f_q) + mstore(19200, result) } - mstore(0x4b00, mulmod(mload(0x4ae0), mload(0x42e0), f_q)) - mstore(0x4b20, mulmod(sub(f_q, mload(0x4b00)), mload(0x4360), f_q)) - mstore(0x4b40, mulmod(mload(0x47c0), mload(0x4360), f_q)) - mstore(0x4b60, addmod(mload(0x4ac0), mload(0x4b20), f_q)) + mstore(0x4b20, mulmod(mload(0x4b00), mload(0x4300), f_q)) + mstore(0x4b40, mulmod(sub(f_q, mload(0x4b20)), mload(0x4380), f_q)) + mstore(0x4b60, mulmod(mload(0x47e0), mload(0x4380), f_q)) + mstore(0x4b80, addmod(mload(0x4ae0), mload(0x4b40), f_q)) { - let result := mulmod(mload(0xc00), mload(0x3e20), f_q) - mstore(19328, result) + let result := mulmod(mload(0xc00), mload(0x3e40), f_q) + mstore(19360, result) } - mstore(0x4ba0, mulmod(mload(0x4b80), mload(0x42e0), f_q)) - mstore(0x4bc0, mulmod(sub(f_q, mload(0x4ba0)), mload(0x4380), f_q)) - mstore(0x4be0, mulmod(mload(0x47c0), mload(0x4380), f_q)) - mstore(0x4c00, addmod(mload(0x4b60), mload(0x4bc0), f_q)) + mstore(0x4bc0, mulmod(mload(0x4ba0), mload(0x4300), f_q)) + mstore(0x4be0, mulmod(sub(f_q, mload(0x4bc0)), mload(0x43a0), f_q)) + mstore(0x4c00, mulmod(mload(0x47e0), mload(0x43a0), f_q)) + mstore(0x4c20, addmod(mload(0x4b80), mload(0x4be0), f_q)) { - let result := mulmod(mload(0xc20), mload(0x3e20), f_q) - mstore(19488, result) + let result := mulmod(mload(0xc20), mload(0x3e40), f_q) + mstore(19520, result) } - mstore(0x4c40, mulmod(mload(0x4c20), mload(0x42e0), f_q)) - mstore(0x4c60, mulmod(sub(f_q, mload(0x4c40)), mload(0x43a0), f_q)) - mstore(0x4c80, mulmod(mload(0x47c0), mload(0x43a0), f_q)) - mstore(0x4ca0, addmod(mload(0x4c00), mload(0x4c60), f_q)) - mstore(0x4cc0, mulmod(mload(0x3880), mload(0x4120), f_q)) - mstore(0x4ce0, mulmod(mload(0x38a0), mload(0x4120), f_q)) - mstore(0x4d00, mulmod(mload(0x38c0), mload(0x4120), f_q)) + mstore(0x4c60, mulmod(mload(0x4c40), mload(0x4300), f_q)) + mstore(0x4c80, mulmod(sub(f_q, mload(0x4c60)), mload(0x43c0), f_q)) + mstore(0x4ca0, mulmod(mload(0x47e0), mload(0x43c0), f_q)) + mstore(0x4cc0, addmod(mload(0x4c20), mload(0x4c80), f_q)) + mstore(0x4ce0, mulmod(mload(0x38a0), mload(0x4140), f_q)) + mstore(0x4d00, mulmod(mload(0x38c0), mload(0x4140), f_q)) + mstore(0x4d20, mulmod(mload(0x38e0), mload(0x4140), f_q)) { - let result := mulmod(mload(0x38e0), mload(0x3e20), f_q) - mstore(19744, result) + let result := mulmod(mload(0x3900), mload(0x3e40), f_q) + mstore(19776, result) } - mstore(0x4d40, mulmod(mload(0x4d20), mload(0x42e0), f_q)) - mstore(0x4d60, mulmod(sub(f_q, mload(0x4d40)), mload(0x43c0), f_q)) - mstore(0x4d80, mulmod(mload(0x47c0), mload(0x43c0), f_q)) - mstore(0x4da0, mulmod(mload(0x4cc0), mload(0x43c0), f_q)) - mstore(0x4dc0, mulmod(mload(0x4ce0), mload(0x43c0), f_q)) - mstore(0x4de0, mulmod(mload(0x4d00), mload(0x43c0), f_q)) - mstore(0x4e00, addmod(mload(0x4ca0), mload(0x4d60), f_q)) + mstore(0x4d60, mulmod(mload(0x4d40), mload(0x4300), f_q)) + mstore(0x4d80, mulmod(sub(f_q, mload(0x4d60)), mload(0x43e0), f_q)) + mstore(0x4da0, mulmod(mload(0x47e0), mload(0x43e0), f_q)) + mstore(0x4dc0, mulmod(mload(0x4ce0), mload(0x43e0), f_q)) + mstore(0x4de0, mulmod(mload(0x4d00), mload(0x43e0), f_q)) + mstore(0x4e00, mulmod(mload(0x4d20), mload(0x43e0), f_q)) + mstore(0x4e20, addmod(mload(0x4cc0), mload(0x4d80), f_q)) { - let result := mulmod(mload(0xbc0), mload(0x3e20), f_q) - mstore(20000, result) + let result := mulmod(mload(0xbc0), mload(0x3e40), f_q) + mstore(20032, result) } - mstore(0x4e40, mulmod(mload(0x4e20), mload(0x42e0), f_q)) - mstore(0x4e60, mulmod(sub(f_q, mload(0x4e40)), mload(0x43e0), f_q)) - mstore(0x4e80, mulmod(mload(0x47c0), mload(0x43e0), f_q)) - mstore(0x4ea0, addmod(mload(0x4e00), mload(0x4e60), f_q)) - mstore(0x4ec0, mulmod(mload(0x4ea0), mload(0x4440), f_q)) - mstore(0x4ee0, mulmod(mload(0x4840), mload(0x4440), f_q)) - mstore(0x4f00, mulmod(mload(0x48c0), mload(0x4440), f_q)) - mstore(0x4f20, mulmod(mload(0x4960), mload(0x4440), f_q)) - mstore(0x4f40, mulmod(mload(0x4a00), mload(0x4440), f_q)) - mstore(0x4f60, mulmod(mload(0x4aa0), mload(0x4440), f_q)) - mstore(0x4f80, mulmod(mload(0x4b40), mload(0x4440), f_q)) - mstore(0x4fa0, mulmod(mload(0x4be0), mload(0x4440), f_q)) - mstore(0x4fc0, mulmod(mload(0x4c80), mload(0x4440), f_q)) - mstore(0x4fe0, mulmod(mload(0x4d80), mload(0x4440), f_q)) - mstore(0x5000, mulmod(mload(0x4da0), mload(0x4440), f_q)) - mstore(0x5020, mulmod(mload(0x4dc0), mload(0x4440), f_q)) - mstore(0x5040, mulmod(mload(0x4de0), mload(0x4440), f_q)) - mstore(0x5060, mulmod(mload(0x4e80), mload(0x4440), f_q)) - mstore(0x5080, addmod(mload(0x47a0), mload(0x4ec0), f_q)) - mstore(0x50a0, mulmod(1, mload(0x3c60), f_q)) - mstore(0x50c0, mulmod(1, mload(0xe40), f_q)) - mstore(0x50e0, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(0x5100, 0x0000000000000000000000000000000000000000000000000000000000000002) - mstore(0x5120, mload(0x5080)) - success := and(eq(staticcall(gas(), 0x7, 0x50e0, 0x60, 0x50e0, 0x40), 1), success) - mstore(0x5140, mload(0x50e0)) + mstore(0x4e60, mulmod(mload(0x4e40), mload(0x4300), f_q)) + mstore(0x4e80, mulmod(sub(f_q, mload(0x4e60)), mload(0x4400), f_q)) + mstore(0x4ea0, mulmod(mload(0x47e0), mload(0x4400), f_q)) + mstore(0x4ec0, addmod(mload(0x4e20), mload(0x4e80), f_q)) + mstore(0x4ee0, mulmod(mload(0x4ec0), mload(0x4460), f_q)) + mstore(0x4f00, mulmod(mload(0x4860), mload(0x4460), f_q)) + mstore(0x4f20, mulmod(mload(0x48e0), mload(0x4460), f_q)) + mstore(0x4f40, mulmod(mload(0x4980), mload(0x4460), f_q)) + mstore(0x4f60, mulmod(mload(0x4a20), mload(0x4460), f_q)) + mstore(0x4f80, mulmod(mload(0x4ac0), mload(0x4460), f_q)) + mstore(0x4fa0, mulmod(mload(0x4b60), mload(0x4460), f_q)) + mstore(0x4fc0, mulmod(mload(0x4c00), mload(0x4460), f_q)) + mstore(0x4fe0, mulmod(mload(0x4ca0), mload(0x4460), f_q)) + mstore(0x5000, mulmod(mload(0x4da0), mload(0x4460), f_q)) + mstore(0x5020, mulmod(mload(0x4dc0), mload(0x4460), f_q)) + mstore(0x5040, mulmod(mload(0x4de0), mload(0x4460), f_q)) + mstore(0x5060, mulmod(mload(0x4e00), mload(0x4460), f_q)) + mstore(0x5080, mulmod(mload(0x4ea0), mload(0x4460), f_q)) + mstore(0x50a0, addmod(mload(0x47c0), mload(0x4ee0), f_q)) + mstore(0x50c0, mulmod(1, mload(0x3c80), f_q)) + mstore(0x50e0, mulmod(1, mload(0xe40), f_q)) + mstore(0x5100, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x5120, 0x0000000000000000000000000000000000000000000000000000000000000002) + mstore(0x5140, mload(0x50a0)) + success := and(eq(staticcall(gas(), 0x7, 0x5100, 0x60, 0x5100, 0x40), 1), success) mstore(0x5160, mload(0x5100)) - mstore(0x5180, mload(0x660)) - mstore(0x51a0, mload(0x680)) - success := and(eq(staticcall(gas(), 0x6, 0x5140, 0x80, 0x5140, 0x40), 1), success) - mstore(0x51c0, mload(0x840)) - mstore(0x51e0, mload(0x860)) - mstore(0x5200, mload(0x4660)) - success := and(eq(staticcall(gas(), 0x7, 0x51c0, 0x60, 0x51c0, 0x40), 1), success) - mstore(0x5220, mload(0x5140)) + mstore(0x5180, mload(0x5120)) + mstore(0x51a0, mload(0x660)) + mstore(0x51c0, mload(0x680)) + success := and(eq(staticcall(gas(), 0x6, 0x5160, 0x80, 0x5160, 0x40), 1), success) + mstore(0x51e0, mload(0x840)) + mstore(0x5200, mload(0x860)) + mstore(0x5220, mload(0x4680)) + success := and(eq(staticcall(gas(), 0x7, 0x51e0, 0x60, 0x51e0, 0x40), 1), success) mstore(0x5240, mload(0x5160)) - mstore(0x5260, mload(0x51c0)) + mstore(0x5260, mload(0x5180)) mstore(0x5280, mload(0x51e0)) - success := and(eq(staticcall(gas(), 0x6, 0x5220, 0x80, 0x5220, 0x40), 1), success) - mstore(0x52a0, mload(0x880)) - mstore(0x52c0, mload(0x8a0)) - mstore(0x52e0, mload(0x4680)) - success := and(eq(staticcall(gas(), 0x7, 0x52a0, 0x60, 0x52a0, 0x40), 1), success) - mstore(0x5300, mload(0x5220)) + mstore(0x52a0, mload(0x5200)) + success := and(eq(staticcall(gas(), 0x6, 0x5240, 0x80, 0x5240, 0x40), 1), success) + mstore(0x52c0, mload(0x880)) + mstore(0x52e0, mload(0x8a0)) + mstore(0x5300, mload(0x46a0)) + success := and(eq(staticcall(gas(), 0x7, 0x52c0, 0x60, 0x52c0, 0x40), 1), success) mstore(0x5320, mload(0x5240)) - mstore(0x5340, mload(0x52a0)) + mstore(0x5340, mload(0x5260)) mstore(0x5360, mload(0x52c0)) - success := and(eq(staticcall(gas(), 0x6, 0x5300, 0x80, 0x5300, 0x40), 1), success) - mstore(0x5380, mload(0x700)) - mstore(0x53a0, mload(0x720)) - mstore(0x53c0, mload(0x4780)) - success := and(eq(staticcall(gas(), 0x7, 0x5380, 0x60, 0x5380, 0x40), 1), success) - mstore(0x53e0, mload(0x5300)) + mstore(0x5380, mload(0x52e0)) + success := and(eq(staticcall(gas(), 0x6, 0x5320, 0x80, 0x5320, 0x40), 1), success) + mstore(0x53a0, mload(0x700)) + mstore(0x53c0, mload(0x720)) + mstore(0x53e0, mload(0x47a0)) + success := and(eq(staticcall(gas(), 0x7, 0x53a0, 0x60, 0x53a0, 0x40), 1), success) mstore(0x5400, mload(0x5320)) - mstore(0x5420, mload(0x5380)) + mstore(0x5420, mload(0x5340)) mstore(0x5440, mload(0x53a0)) - success := and(eq(staticcall(gas(), 0x6, 0x53e0, 0x80, 0x53e0, 0x40), 1), success) - mstore(0x5460, mload(0x740)) - mstore(0x5480, mload(0x760)) - mstore(0x54a0, mload(0x4ee0)) - success := and(eq(staticcall(gas(), 0x7, 0x5460, 0x60, 0x5460, 0x40), 1), success) - mstore(0x54c0, mload(0x53e0)) + mstore(0x5460, mload(0x53c0)) + success := and(eq(staticcall(gas(), 0x6, 0x5400, 0x80, 0x5400, 0x40), 1), success) + mstore(0x5480, mload(0x740)) + mstore(0x54a0, mload(0x760)) + mstore(0x54c0, mload(0x4f00)) + success := and(eq(staticcall(gas(), 0x7, 0x5480, 0x60, 0x5480, 0x40), 1), success) mstore(0x54e0, mload(0x5400)) - mstore(0x5500, mload(0x5460)) + mstore(0x5500, mload(0x5420)) mstore(0x5520, mload(0x5480)) - success := and(eq(staticcall(gas(), 0x6, 0x54c0, 0x80, 0x54c0, 0x40), 1), success) - mstore(0x5540, 0x04633090806662534335356654f3ee6430f215f4f010ae32ae068a900596d598) - mstore(0x5560, 0x2559e379146d41a440431d5bcb5ebdf2f978e08999ccf6cfff2586402050780f) - mstore(0x5580, mload(0x4f00)) - success := and(eq(staticcall(gas(), 0x7, 0x5540, 0x60, 0x5540, 0x40), 1), success) - mstore(0x55a0, mload(0x54c0)) + mstore(0x5540, mload(0x54a0)) + success := and(eq(staticcall(gas(), 0x6, 0x54e0, 0x80, 0x54e0, 0x40), 1), success) + mstore(0x5560, 0x28c9feac830a1d23683f2a635ca9232fd5a627948b2a063e04edbbd5df806073) + mstore(0x5580, 0x098706d829dcb3f6fcc0df885174a2a2de081c590a00ac95f4525f60babbefe9) + mstore(0x55a0, mload(0x4f20)) + success := and(eq(staticcall(gas(), 0x7, 0x5560, 0x60, 0x5560, 0x40), 1), success) mstore(0x55c0, mload(0x54e0)) - mstore(0x55e0, mload(0x5540)) + mstore(0x55e0, mload(0x5500)) mstore(0x5600, mload(0x5560)) - success := and(eq(staticcall(gas(), 0x6, 0x55a0, 0x80, 0x55a0, 0x40), 1), success) - mstore(0x5620, 0x2eb40e2b0c13a6f4b989cffa9dbc452447bfd9f04a79f6379aefea8c9850a550) - mstore(0x5640, 0x0efe5496541e2bd648d490f11ad542e1dec3127f818b8065843d0dd81358416c) - mstore(0x5660, mload(0x4f20)) - success := and(eq(staticcall(gas(), 0x7, 0x5620, 0x60, 0x5620, 0x40), 1), success) - mstore(0x5680, mload(0x55a0)) + mstore(0x5620, mload(0x5580)) + success := and(eq(staticcall(gas(), 0x6, 0x55c0, 0x80, 0x55c0, 0x40), 1), success) + mstore(0x5640, 0x03847d4de6cbde8c639401cf45f0db7c7c8385ca483825448b5ba614691f53e6) + mstore(0x5660, 0x0147b0ddc70c95e5285d289c54c930e5782d755366f5d3d0dc8376f01f47981e) + mstore(0x5680, mload(0x4f40)) + success := and(eq(staticcall(gas(), 0x7, 0x5640, 0x60, 0x5640, 0x40), 1), success) mstore(0x56a0, mload(0x55c0)) - mstore(0x56c0, mload(0x5620)) + mstore(0x56c0, mload(0x55e0)) mstore(0x56e0, mload(0x5640)) - success := and(eq(staticcall(gas(), 0x6, 0x5680, 0x80, 0x5680, 0x40), 1), success) - mstore(0x5700, 0x18dca54423b6fa7932c92beff56ce260a3c726e3613c92fe0843d86b92199bfd) - mstore(0x5720, 0x0f6641ca942a4541625b14adb25ab0fd978060c98d01eb1b036fcdb1b8f77be1) - mstore(0x5740, mload(0x4f40)) - success := and(eq(staticcall(gas(), 0x7, 0x5700, 0x60, 0x5700, 0x40), 1), success) - mstore(0x5760, mload(0x5680)) + mstore(0x5700, mload(0x5660)) + success := and(eq(staticcall(gas(), 0x6, 0x56a0, 0x80, 0x56a0, 0x40), 1), success) + mstore(0x5720, 0x03a22feeb728a985ba1a7267babd2972060351c1893e8c9d1b4afea1997cfb2d) + mstore(0x5740, 0x0f00b29e6e16328160b696c3e2c5d909f07915a12997bd55dd0b029c4693f6d6) + mstore(0x5760, mload(0x4f60)) + success := and(eq(staticcall(gas(), 0x7, 0x5720, 0x60, 0x5720, 0x40), 1), success) mstore(0x5780, mload(0x56a0)) - mstore(0x57a0, mload(0x5700)) + mstore(0x57a0, mload(0x56c0)) mstore(0x57c0, mload(0x5720)) - success := and(eq(staticcall(gas(), 0x6, 0x5760, 0x80, 0x5760, 0x40), 1), success) - mstore(0x57e0, 0x23809cc9d17a8cb32381764c6234d3038148b8bec5d8573fb3470486feedd968) - mstore(0x5800, 0x1debabb870ec20dc2c4df55cbd88205b6dd234ad5805faf3a72e14b6f934f238) - mstore(0x5820, mload(0x4f60)) - success := and(eq(staticcall(gas(), 0x7, 0x57e0, 0x60, 0x57e0, 0x40), 1), success) - mstore(0x5840, mload(0x5760)) + mstore(0x57e0, mload(0x5740)) + success := and(eq(staticcall(gas(), 0x6, 0x5780, 0x80, 0x5780, 0x40), 1), success) + mstore(0x5800, 0x280c2465cda2991f784c170550813f50400fd1e437adc86a2d7c2f12d6ccece9) + mstore(0x5820, 0x10a8f946db6ebc615b792f6b4f0d5522c1ade32208d2cb6b1019a9321314546e) + mstore(0x5840, mload(0x4f80)) + success := and(eq(staticcall(gas(), 0x7, 0x5800, 0x60, 0x5800, 0x40), 1), success) mstore(0x5860, mload(0x5780)) - mstore(0x5880, mload(0x57e0)) + mstore(0x5880, mload(0x57a0)) mstore(0x58a0, mload(0x5800)) - success := and(eq(staticcall(gas(), 0x6, 0x5840, 0x80, 0x5840, 0x40), 1), success) - mstore(0x58c0, 0x10ff9174af9a7540d6335a6dad3dd0fe0c3943b24b706ba111c73534218c8d99) - mstore(0x58e0, 0x07769bf2a7e819b8b069c49481451ca34b9cfe9cf4ab6c03709a3b33aa9f25f9) - mstore(0x5900, mload(0x4f80)) - success := and(eq(staticcall(gas(), 0x7, 0x58c0, 0x60, 0x58c0, 0x40), 1), success) - mstore(0x5920, mload(0x5840)) + mstore(0x58c0, mload(0x5820)) + success := and(eq(staticcall(gas(), 0x6, 0x5860, 0x80, 0x5860, 0x40), 1), success) + mstore(0x58e0, 0x1ecade5ea10ab9a44d2993527fc6263bd9148efb451b2eda13141156ff68104a) + mstore(0x5900, 0x2d541cb34d01ce121940240afcdc8ede1d387be66ce2c56acfe3adde7030850d) + mstore(0x5920, mload(0x4fa0)) + success := and(eq(staticcall(gas(), 0x7, 0x58e0, 0x60, 0x58e0, 0x40), 1), success) mstore(0x5940, mload(0x5860)) - mstore(0x5960, mload(0x58c0)) + mstore(0x5960, mload(0x5880)) mstore(0x5980, mload(0x58e0)) - success := and(eq(staticcall(gas(), 0x6, 0x5920, 0x80, 0x5920, 0x40), 1), success) - mstore(0x59a0, 0x2347cc725aa8ab0c70557e7effada9a02cba0277f8aca1785f986430d8b63ad4) - mstore(0x59c0, 0x2f7f8f66561183dd0a7c6cf12a1fa248b80509334c8e87dbdcf192301a3c6a4d) - mstore(0x59e0, mload(0x4fa0)) - success := and(eq(staticcall(gas(), 0x7, 0x59a0, 0x60, 0x59a0, 0x40), 1), success) - mstore(0x5a00, mload(0x5920)) + mstore(0x59a0, mload(0x5900)) + success := and(eq(staticcall(gas(), 0x6, 0x5940, 0x80, 0x5940, 0x40), 1), success) + mstore(0x59c0, 0x1f7ec4a8e2d1dc36ac3029083025a40f990139b0d508385cb50e58cb9a90d09f) + mstore(0x59e0, 0x1977fe3123b724391fee488dc63a61ee240ea7ddb6b24b11cfbb0b96dff676b5) + mstore(0x5a00, mload(0x4fc0)) + success := and(eq(staticcall(gas(), 0x7, 0x59c0, 0x60, 0x59c0, 0x40), 1), success) mstore(0x5a20, mload(0x5940)) - mstore(0x5a40, mload(0x59a0)) + mstore(0x5a40, mload(0x5960)) mstore(0x5a60, mload(0x59c0)) - success := and(eq(staticcall(gas(), 0x6, 0x5a00, 0x80, 0x5a00, 0x40), 1), success) - mstore(0x5a80, 0x23eb59f4643a8f86f1bb54ebc274b4810126c9c2fae5d8de472ef0566afaa14c) - mstore(0x5aa0, 0x13b28c9220c717cac368247913075f4bb8da09cd9d0145c1292810854089c39c) - mstore(0x5ac0, mload(0x4fc0)) - success := and(eq(staticcall(gas(), 0x7, 0x5a80, 0x60, 0x5a80, 0x40), 1), success) - mstore(0x5ae0, mload(0x5a00)) + mstore(0x5a80, mload(0x59e0)) + success := and(eq(staticcall(gas(), 0x6, 0x5a20, 0x80, 0x5a20, 0x40), 1), success) + mstore(0x5aa0, 0x06df94a5af1833345174baa17f9bc72e984b7fe5844f8a5f4f67d049eacc18b5) + mstore(0x5ac0, 0x04f4452609f3a6ab5d471fd2e86383802e7a921b86b36219f446043d79e2fd78) + mstore(0x5ae0, mload(0x4fe0)) + success := and(eq(staticcall(gas(), 0x7, 0x5aa0, 0x60, 0x5aa0, 0x40), 1), success) mstore(0x5b00, mload(0x5a20)) - mstore(0x5b20, mload(0x5a80)) + mstore(0x5b20, mload(0x5a40)) mstore(0x5b40, mload(0x5aa0)) - success := and(eq(staticcall(gas(), 0x6, 0x5ae0, 0x80, 0x5ae0, 0x40), 1), success) - mstore(0x5b60, mload(0x960)) - mstore(0x5b80, mload(0x980)) - mstore(0x5ba0, mload(0x4fe0)) - success := and(eq(staticcall(gas(), 0x7, 0x5b60, 0x60, 0x5b60, 0x40), 1), success) - mstore(0x5bc0, mload(0x5ae0)) + mstore(0x5b60, mload(0x5ac0)) + success := and(eq(staticcall(gas(), 0x6, 0x5b00, 0x80, 0x5b00, 0x40), 1), success) + mstore(0x5b80, mload(0x960)) + mstore(0x5ba0, mload(0x980)) + mstore(0x5bc0, mload(0x5000)) + success := and(eq(staticcall(gas(), 0x7, 0x5b80, 0x60, 0x5b80, 0x40), 1), success) mstore(0x5be0, mload(0x5b00)) - mstore(0x5c00, mload(0x5b60)) + mstore(0x5c00, mload(0x5b20)) mstore(0x5c20, mload(0x5b80)) - success := and(eq(staticcall(gas(), 0x6, 0x5bc0, 0x80, 0x5bc0, 0x40), 1), success) - mstore(0x5c40, mload(0x9a0)) - mstore(0x5c60, mload(0x9c0)) - mstore(0x5c80, mload(0x5000)) - success := and(eq(staticcall(gas(), 0x7, 0x5c40, 0x60, 0x5c40, 0x40), 1), success) - mstore(0x5ca0, mload(0x5bc0)) + mstore(0x5c40, mload(0x5ba0)) + success := and(eq(staticcall(gas(), 0x6, 0x5be0, 0x80, 0x5be0, 0x40), 1), success) + mstore(0x5c60, mload(0x9a0)) + mstore(0x5c80, mload(0x9c0)) + mstore(0x5ca0, mload(0x5020)) + success := and(eq(staticcall(gas(), 0x7, 0x5c60, 0x60, 0x5c60, 0x40), 1), success) mstore(0x5cc0, mload(0x5be0)) - mstore(0x5ce0, mload(0x5c40)) + mstore(0x5ce0, mload(0x5c00)) mstore(0x5d00, mload(0x5c60)) - success := and(eq(staticcall(gas(), 0x6, 0x5ca0, 0x80, 0x5ca0, 0x40), 1), success) - mstore(0x5d20, mload(0x9e0)) - mstore(0x5d40, mload(0xa00)) - mstore(0x5d60, mload(0x5020)) - success := and(eq(staticcall(gas(), 0x7, 0x5d20, 0x60, 0x5d20, 0x40), 1), success) - mstore(0x5d80, mload(0x5ca0)) + mstore(0x5d20, mload(0x5c80)) + success := and(eq(staticcall(gas(), 0x6, 0x5cc0, 0x80, 0x5cc0, 0x40), 1), success) + mstore(0x5d40, mload(0x9e0)) + mstore(0x5d60, mload(0xa00)) + mstore(0x5d80, mload(0x5040)) + success := and(eq(staticcall(gas(), 0x7, 0x5d40, 0x60, 0x5d40, 0x40), 1), success) mstore(0x5da0, mload(0x5cc0)) - mstore(0x5dc0, mload(0x5d20)) + mstore(0x5dc0, mload(0x5ce0)) mstore(0x5de0, mload(0x5d40)) - success := and(eq(staticcall(gas(), 0x6, 0x5d80, 0x80, 0x5d80, 0x40), 1), success) - mstore(0x5e00, mload(0xa20)) - mstore(0x5e20, mload(0xa40)) - mstore(0x5e40, mload(0x5040)) - success := and(eq(staticcall(gas(), 0x7, 0x5e00, 0x60, 0x5e00, 0x40), 1), success) - mstore(0x5e60, mload(0x5d80)) + mstore(0x5e00, mload(0x5d60)) + success := and(eq(staticcall(gas(), 0x6, 0x5da0, 0x80, 0x5da0, 0x40), 1), success) + mstore(0x5e20, mload(0xa20)) + mstore(0x5e40, mload(0xa40)) + mstore(0x5e60, mload(0x5060)) + success := and(eq(staticcall(gas(), 0x7, 0x5e20, 0x60, 0x5e20, 0x40), 1), success) mstore(0x5e80, mload(0x5da0)) - mstore(0x5ea0, mload(0x5e00)) + mstore(0x5ea0, mload(0x5dc0)) mstore(0x5ec0, mload(0x5e20)) - success := and(eq(staticcall(gas(), 0x6, 0x5e60, 0x80, 0x5e60, 0x40), 1), success) - mstore(0x5ee0, mload(0x8c0)) - mstore(0x5f00, mload(0x8e0)) - mstore(0x5f20, mload(0x5060)) - success := and(eq(staticcall(gas(), 0x7, 0x5ee0, 0x60, 0x5ee0, 0x40), 1), success) - mstore(0x5f40, mload(0x5e60)) + mstore(0x5ee0, mload(0x5e40)) + success := and(eq(staticcall(gas(), 0x6, 0x5e80, 0x80, 0x5e80, 0x40), 1), success) + mstore(0x5f00, mload(0x8c0)) + mstore(0x5f20, mload(0x8e0)) + mstore(0x5f40, mload(0x5080)) + success := and(eq(staticcall(gas(), 0x7, 0x5f00, 0x60, 0x5f00, 0x40), 1), success) mstore(0x5f60, mload(0x5e80)) - mstore(0x5f80, mload(0x5ee0)) + mstore(0x5f80, mload(0x5ea0)) mstore(0x5fa0, mload(0x5f00)) - success := and(eq(staticcall(gas(), 0x6, 0x5f40, 0x80, 0x5f40, 0x40), 1), success) - mstore(0x5fc0, mload(0xde0)) - mstore(0x5fe0, mload(0xe00)) - mstore(0x6000, sub(f_q, mload(0x50a0))) - success := and(eq(staticcall(gas(), 0x7, 0x5fc0, 0x60, 0x5fc0, 0x40), 1), success) - mstore(0x6020, mload(0x5f40)) + mstore(0x5fc0, mload(0x5f20)) + success := and(eq(staticcall(gas(), 0x6, 0x5f60, 0x80, 0x5f60, 0x40), 1), success) + mstore(0x5fe0, mload(0xde0)) + mstore(0x6000, mload(0xe00)) + mstore(0x6020, sub(f_q, mload(0x50c0))) + success := and(eq(staticcall(gas(), 0x7, 0x5fe0, 0x60, 0x5fe0, 0x40), 1), success) mstore(0x6040, mload(0x5f60)) - mstore(0x6060, mload(0x5fc0)) + mstore(0x6060, mload(0x5f80)) mstore(0x6080, mload(0x5fe0)) - success := and(eq(staticcall(gas(), 0x6, 0x6020, 0x80, 0x6020, 0x40), 1), success) - mstore(0x60a0, mload(0xe80)) - mstore(0x60c0, mload(0xea0)) - mstore(0x60e0, mload(0x50c0)) - success := and(eq(staticcall(gas(), 0x7, 0x60a0, 0x60, 0x60a0, 0x40), 1), success) - mstore(0x6100, mload(0x6020)) + mstore(0x60a0, mload(0x6000)) + success := and(eq(staticcall(gas(), 0x6, 0x6040, 0x80, 0x6040, 0x40), 1), success) + mstore(0x60c0, mload(0xe80)) + mstore(0x60e0, mload(0xea0)) + mstore(0x6100, mload(0x50e0)) + success := and(eq(staticcall(gas(), 0x7, 0x60c0, 0x60, 0x60c0, 0x40), 1), success) mstore(0x6120, mload(0x6040)) - mstore(0x6140, mload(0x60a0)) + mstore(0x6140, mload(0x6060)) mstore(0x6160, mload(0x60c0)) - success := and(eq(staticcall(gas(), 0x6, 0x6100, 0x80, 0x6100, 0x40), 1), success) - mstore(0x6180, mload(0x6100)) + mstore(0x6180, mload(0x60e0)) + success := and(eq(staticcall(gas(), 0x6, 0x6120, 0x80, 0x6120, 0x40), 1), success) mstore(0x61a0, mload(0x6120)) - mstore(0x61c0, mload(0xe80)) - mstore(0x61e0, mload(0xea0)) - mstore(0x6200, mload(0xec0)) - mstore(0x6220, mload(0xee0)) - mstore(0x6240, mload(0xf00)) - mstore(0x6260, mload(0xf20)) - mstore(0x6280, keccak256(0x6180, 256)) - mstore(25248, mod(mload(25216), f_q)) - mstore(0x62c0, mulmod(mload(0x62a0), mload(0x62a0), f_q)) - mstore(0x62e0, mulmod(1, mload(0x62a0), f_q)) - mstore(0x6300, mload(0x6200)) + mstore(0x61c0, mload(0x6140)) + mstore(0x61e0, mload(0xe80)) + mstore(0x6200, mload(0xea0)) + mstore(0x6220, mload(0xec0)) + mstore(0x6240, mload(0xee0)) + mstore(0x6260, mload(0xf00)) + mstore(0x6280, mload(0xf20)) + mstore(0x62a0, keccak256(0x61a0, 256)) + mstore(25280, mod(mload(25248), f_q)) + mstore(0x62e0, mulmod(mload(0x62c0), mload(0x62c0), f_q)) + mstore(0x6300, mulmod(1, mload(0x62c0), f_q)) mstore(0x6320, mload(0x6220)) - mstore(0x6340, mload(0x62e0)) - success := and(eq(staticcall(gas(), 0x7, 0x6300, 0x60, 0x6300, 0x40), 1), success) - mstore(0x6360, mload(0x6180)) + mstore(0x6340, mload(0x6240)) + mstore(0x6360, mload(0x6300)) + success := and(eq(staticcall(gas(), 0x7, 0x6320, 0x60, 0x6320, 0x40), 1), success) mstore(0x6380, mload(0x61a0)) - mstore(0x63a0, mload(0x6300)) + mstore(0x63a0, mload(0x61c0)) mstore(0x63c0, mload(0x6320)) - success := and(eq(staticcall(gas(), 0x6, 0x6360, 0x80, 0x6360, 0x40), 1), success) - mstore(0x63e0, mload(0x6240)) + mstore(0x63e0, mload(0x6340)) + success := and(eq(staticcall(gas(), 0x6, 0x6380, 0x80, 0x6380, 0x40), 1), success) mstore(0x6400, mload(0x6260)) - mstore(0x6420, mload(0x62e0)) - success := and(eq(staticcall(gas(), 0x7, 0x63e0, 0x60, 0x63e0, 0x40), 1), success) - mstore(0x6440, mload(0x61c0)) + mstore(0x6420, mload(0x6280)) + mstore(0x6440, mload(0x6300)) + success := and(eq(staticcall(gas(), 0x7, 0x6400, 0x60, 0x6400, 0x40), 1), success) mstore(0x6460, mload(0x61e0)) - mstore(0x6480, mload(0x63e0)) + mstore(0x6480, mload(0x6200)) mstore(0x64a0, mload(0x6400)) - success := and(eq(staticcall(gas(), 0x6, 0x6440, 0x80, 0x6440, 0x40), 1), success) - mstore(0x64c0, mload(0x6360)) + mstore(0x64c0, mload(0x6420)) + success := and(eq(staticcall(gas(), 0x6, 0x6460, 0x80, 0x6460, 0x40), 1), success) mstore(0x64e0, mload(0x6380)) - mstore(0x6500, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) - mstore(0x6520, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x6540, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0x6560, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) - mstore(0x6580, mload(0x6440)) + mstore(0x6500, mload(0x63a0)) + mstore(0x6520, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0x6540, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x6560, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0x6580, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) mstore(0x65a0, mload(0x6460)) - mstore(0x65c0, 0x172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b) - mstore(0x65e0, 0x2ae0c8c3a090f7200ff398ee9845bbae8f8c1445ae7b632212775f60a0e21600) - mstore(0x6600, 0x190fa476a5b352809ed41d7a0d7fe12b8f685e3c12a6d83855dba27aaf469643) - mstore(0x6620, 0x1c0a500618907df9e4273d5181e31088deb1f05132de037cbfe73888f97f77c9) - success := and(eq(staticcall(gas(), 0x8, 0x64c0, 0x180, 0x64c0, 0x20), 1), success) - success := and(eq(mload(0x64c0), 1), success) + mstore(0x65c0, mload(0x6480)) + mstore(0x65e0, 0x172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b) + mstore(0x6600, 0x2ae0c8c3a090f7200ff398ee9845bbae8f8c1445ae7b632212775f60a0e21600) + mstore(0x6620, 0x190fa476a5b352809ed41d7a0d7fe12b8f685e3c12a6d83855dba27aaf469643) + mstore(0x6640, 0x1c0a500618907df9e4273d5181e31088deb1f05132de037cbfe73888f97f77c9) + success := and(eq(staticcall(gas(), 0x8, 0x64e0, 0x180, 0x64e0, 0x20), 1), success) + success := and(eq(mload(0x64e0), 1), success) // Revert if anything fails if iszero(success) { revert(0, 0) } diff --git a/scripts/build-and-run.sh b/scripts/build-and-run.sh index 73b1fe9a..024aebcb 100644 --- a/scripts/build-and-run.sh +++ b/scripts/build-and-run.sh @@ -1,3 +1,6 @@ set -euxo pipefail +#make build-guest-local 2>&1 | tee build.log make build-guest 2>&1 | tee build.log -make test-e2e-bundle 2>&1 | tee e2e.log +#OUTPUT_PATH=`realpath .output/bundle-tests-20251113_053106/` GPU=1 make test-e2e-bundle 2>&1 | tee e2e.log +#GUEST_VERSION=0.5.2 +GPU=1 make test-e2e-bundle 2>&1 | tee e2e.log From 07bd7e70790ff45e972cf30e39ea9ce3ae8ac8cc Mon Sep 17 00:00:00 2001 From: Velaciela Date: Mon, 18 May 2026 20:27:02 +0800 Subject: [PATCH 04/19] update exe commit --- Makefile | 12 ------------ crates/circuits/batch-circuit/batch_exe_commit.rs | 2 +- crates/circuits/bundle-circuit/bundle_exe_commit.rs | 2 +- crates/circuits/chunk-circuit/chunk_exe_commit.rs | 2 +- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 63cabdb1..1c021d89 100644 --- a/Makefile +++ b/Makefile @@ -32,9 +32,6 @@ $(SRS_PARAMS_DIR)/%.srs: download-release: bash download-release.sh -upload-release: - @cargo run --bin scroll-zkvm-upload-axiom - fmt: @cargo fmt --all @@ -93,9 +90,6 @@ test-execute-validium-e2e: test-single-chunk: @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test chunk_circuit setup_prove_verify_single -- --exact --nocapture -test-axiom-single-chunk: - @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test chunk_circuit setup_axiom_prove_verify_single -- --exact --nocapture - test-multi-chunk: @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test chunk_circuit setup_prove_verify_multi -- --exact --nocapture @@ -105,9 +99,6 @@ test-single-batch: test-e2e-batch: @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test batch_circuit e2e -- --exact --nocapture -test-axiom-e2e-batch: - @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test batch_circuit axiom_e2e -- --exact --nocapture - test-bundle: @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test bundle_circuit setup_prove_verify -- --exact --nocapture @@ -116,6 +107,3 @@ test-bundle-local: test-e2e-bundle: @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test bundle_circuit e2e -- --exact --nocapture - -test-axiom-e2e-bundle: - @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test bundle_circuit axiom_e2e -- --exact --nocapture diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 85bacd94..50f9f957 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [574520761, 879677804, 1283141277, 1761929109, 1721107250, 974282683, 435330475, 625449777]; +pub const COMMIT: [u32; 8] = [1941961454, 477170407, 129479363, 346777881, 1960024003, 1085475360, 189100159, 745934103]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 0df06713..def756a5 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [516873274, 1075607986, 1001047012, 1209458940, 427908064, 1922052567, 1750380191, 1968279532]; +pub const COMMIT: [u32; 8] = [1881598004, 970250555, 1933976758, 277699807, 1238449309, 1025509899, 1136847759, 777751013]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index cc204f47..3797e753 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [748412756, 309489192, 1741755255, 1877282487, 564318861, 1368414247, 704142321, 1392145592]; +pub const COMMIT: [u32; 8] = [772167398, 274296420, 122391362, 18861170, 1678047186, 1143048180, 1123167759, 1472433101]; From b1d542d00a69995fed8bba2e684c5673a12b3c60 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Mon, 18 May 2026 20:30:37 +0800 Subject: [PATCH 05/19] fmt --- crates/integration/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 8e56f593..51d20842 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -27,7 +27,6 @@ pub mod testers; pub mod utils; - /// Directory to store proofs on disc. const DIR_PROOFS: &str = "proofs"; From a2820be92c27c467757274134dbdb1b4ce008fb6 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Mon, 18 May 2026 20:40:33 +0800 Subject: [PATCH 06/19] fix some sec issues --- Cargo.lock | 163 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e60a044..e718fc12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,7 +159,7 @@ dependencies = [ "either", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "secp256k1 0.30.0", "serde", "serde_json", @@ -402,7 +402,7 @@ dependencies = [ "keccak-asm", "paste", "proptest", - "rand 0.9.2", + "rand 0.9.4", "ruint", "rustc-hash 2.1.1", "serde", @@ -1097,7 +1097,7 @@ checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "colored", "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1107,7 +1107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1117,7 +1117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1540,9 +1540,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] @@ -2563,7 +2563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.5", + "rand 0.8.6", "rustc-hex", "static_assertions", ] @@ -2871,7 +2871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.1", - "rand 0.8.5", + "rand 0.8.6", "rand_core 0.6.4", "rand_xorshift 0.3.0", "subtle", @@ -2900,7 +2900,7 @@ dependencies = [ "itertools 0.11.0", "maybe-rayon", "pairing 0.23.0", - "rand 0.8.5", + "rand 0.8.6", "rand_core 0.6.4", "rayon", "rustc-hash 1.1.0", @@ -2940,7 +2940,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "rand_chacha 0.3.1", "rand_core 0.6.4", "rayon", @@ -2980,7 +2980,7 @@ dependencies = [ "pairing 0.23.0", "pasta_curves 0.5.1", "paste", - "rand 0.8.5", + "rand 0.8.6", "rand_core 0.6.4", "rayon", "serde", @@ -3007,7 +3007,7 @@ dependencies = [ "pairing 0.23.0", "pasta_curves 0.5.1", "paste", - "rand 0.8.5", + "rand 0.8.6", "rand_core 0.6.4", "rayon", "serde", @@ -3548,9 +3548,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] @@ -3608,7 +3608,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand 0.8.5", + "rand 0.8.6", "serde", "sha2 0.9.9", ] @@ -3909,7 +3909,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "serde", ] @@ -3924,9 +3924,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-integer" @@ -3972,7 +3972,7 @@ dependencies = [ "num-integer", "num-modular", "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -4177,15 +4177,14 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.75" +version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -4209,9 +4208,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" dependencies = [ "cc", "libc", @@ -4261,7 +4260,7 @@ dependencies = [ "openvm-rv32im-circuit", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", "serde", "serde_with", "strum 0.26.3", @@ -4339,7 +4338,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "openvm-transpiler", - "rand 0.9.2", + "rand 0.9.4", "rand_chacha 0.3.1", "tiny-keccak", "tokio", @@ -4383,7 +4382,7 @@ dependencies = [ "openvm-rv32im-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", "serde", ] @@ -4454,7 +4453,7 @@ dependencies = [ "openvm-stark-sdk", "p3-baby-bear", "p3-field", - "rand 0.9.2", + "rand 0.9.4", "rustc-hash 2.1.1", "serde", "serde-big-array", @@ -4488,7 +4487,7 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-stark-backend", - "rand 0.9.2", + "rand 0.9.4", "tracing", ] @@ -4610,7 +4609,7 @@ dependencies = [ "openvm-rv32-adapters", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", "serde", "serde_with", "strum 0.26.3", @@ -4707,7 +4706,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "p3-keccak-air", - "rand 0.9.2", + "rand 0.9.4", "serde", "strum 0.26.3", "tiny-keccak", @@ -4760,8 +4759,8 @@ dependencies = [ "openvm-instructions", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.4", "tracing", ] @@ -4790,7 +4789,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "p3-field", - "rand 0.9.2", + "rand 0.9.4", "serde", "static_assertions", "strum 0.26.3", @@ -4847,8 +4846,8 @@ dependencies = [ "p3-fri", "p3-merkle-tree", "p3-symmetric", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.4", "serde", "serde_json", "serde_with", @@ -4916,7 +4915,7 @@ dependencies = [ "openvm-rv32im-circuit", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", "serde", "strum 0.26.3", ] @@ -4978,7 +4977,7 @@ dependencies = [ "p3-poseidon2", "p3-poseidon2-air", "p3-symmetric", - "rand 0.9.2", + "rand 0.9.4", "zkhash", ] @@ -4996,7 +4995,7 @@ dependencies = [ "openvm-rv32im-circuit", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", ] [[package]] @@ -5021,7 +5020,7 @@ dependencies = [ "openvm-rv32im-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", "serde", "strum 0.26.3", ] @@ -5097,7 +5096,7 @@ dependencies = [ "openvm-transpiler", "p3-bn254", "p3-fri", - "rand 0.9.2", + "rand 0.9.4", "rrs-lib", "serde", "serde_json", @@ -5126,7 +5125,7 @@ source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0 dependencies = [ "openvm-circuit-primitives", "openvm-stark-backend", - "rand 0.9.2", + "rand 0.9.4", "sha2 0.10.9", ] @@ -5150,7 +5149,7 @@ dependencies = [ "openvm-sha256-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "rand 0.9.2", + "rand 0.9.4", "serde", "sha2 0.10.9", "strum 0.26.3", @@ -5232,7 +5231,7 @@ dependencies = [ "p3-poseidon", "p3-poseidon2", "p3-symmetric", - "rand 0.9.2", + "rand 0.9.4", "serde", "serde_json", "static_assertions", @@ -5319,7 +5318,7 @@ dependencies = [ "p3-monty-31", "p3-poseidon2", "p3-symmetric", - "rand 0.9.2", + "rand 0.9.4", ] [[package]] @@ -5345,7 +5344,7 @@ dependencies = [ "p3-symmetric", "p3-util", "paste", - "rand 0.9.2", + "rand 0.9.4", "serde", ] @@ -5404,7 +5403,7 @@ dependencies = [ "p3-maybe-rayon", "p3-util", "paste", - "rand 0.9.2", + "rand 0.9.4", "serde", "tracing", ] @@ -5424,7 +5423,7 @@ dependencies = [ "p3-matrix", "p3-maybe-rayon", "p3-util", - "rand 0.9.2", + "rand 0.9.4", "serde", "thiserror 2.0.17", "tracing", @@ -5445,7 +5444,7 @@ dependencies = [ "p3-symmetric", "p3-util", "paste", - "rand 0.9.2", + "rand 0.9.4", "serde", ] @@ -5484,7 +5483,7 @@ dependencies = [ "p3-matrix", "p3-maybe-rayon", "p3-util", - "rand 0.9.2", + "rand 0.9.4", "tracing", ] @@ -5499,7 +5498,7 @@ dependencies = [ "p3-monty-31", "p3-poseidon2", "p3-symmetric", - "rand 0.9.2", + "rand 0.9.4", ] [[package]] @@ -5512,7 +5511,7 @@ dependencies = [ "p3-field", "p3-maybe-rayon", "p3-util", - "rand 0.9.2", + "rand 0.9.4", "serde", "tracing", ] @@ -5536,7 +5535,7 @@ dependencies = [ "p3-field", "p3-symmetric", "p3-util", - "rand 0.9.2", + "rand 0.9.4", ] [[package]] @@ -5552,7 +5551,7 @@ dependencies = [ "p3-maybe-rayon", "p3-symmetric", "p3-util", - "rand 0.9.2", + "rand 0.9.4", "serde", "thiserror 2.0.17", "tracing", @@ -5575,7 +5574,7 @@ dependencies = [ "p3-symmetric", "p3-util", "paste", - "rand 0.9.2", + "rand 0.9.4", "serde", "spin 0.10.0", "tracing", @@ -5590,7 +5589,7 @@ dependencies = [ "p3-field", "p3-mds", "p3-symmetric", - "rand 0.9.2", + "rand 0.9.4", ] [[package]] @@ -5603,7 +5602,7 @@ dependencies = [ "p3-mds", "p3-symmetric", "p3-util", - "rand 0.9.2", + "rand 0.9.4", ] [[package]] @@ -5617,7 +5616,7 @@ dependencies = [ "p3-matrix", "p3-maybe-rayon", "p3-poseidon2", - "rand 0.9.2", + "rand 0.9.4", "tracing", ] @@ -5721,7 +5720,7 @@ dependencies = [ "ff 0.12.1", "group 0.12.1", "lazy_static", - "rand 0.8.5", + "rand 0.8.6", "static_assertions", "subtle", ] @@ -5736,7 +5735,7 @@ dependencies = [ "ff 0.13.1", "group 0.13.0", "lazy_static", - "rand 0.8.5", + "rand 0.8.6", "static_assertions", "subtle", ] @@ -5792,7 +5791,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -5924,7 +5923,7 @@ dependencies = [ "ff 0.13.1", "lazy_static", "log", - "rand 0.8.5", + "rand 0.8.6", "rand_xorshift 0.3.0", "thiserror 1.0.69", ] @@ -6033,7 +6032,7 @@ dependencies = [ "bit-vec", "bitflags", "num-traits", - "rand 0.9.2", + "rand 0.9.4", "rand_chacha 0.9.0", "rand_xorshift 0.4.0", "regex-syntax", @@ -6106,9 +6105,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -6118,9 +6117,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -7647,8 +7646,8 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.4", "rlp", "ruint-macro", "serde_core", @@ -8236,7 +8235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", + "rand 0.8.6", "secp256k1-sys 0.10.1", "serde", ] @@ -8248,7 +8247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" dependencies = [ "bitcoin_hashes", - "rand 0.9.2", + "rand 0.9.4", "secp256k1-sys 0.11.0", ] @@ -8595,7 +8594,7 @@ dependencies = [ "num-integer", "num-traits", "pairing 0.23.0", - "rand 0.8.5", + "rand 0.8.6", "revm 22.0.1", "ruint", "serde", @@ -8619,7 +8618,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "rand_chacha 0.3.1", "serde", "serde_json", @@ -8955,30 +8954,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -10030,7 +10029,7 @@ dependencies = [ "jubjub", "lazy_static", "pasta_curves 0.5.1", - "rand 0.8.5", + "rand 0.8.6", "serde", "sha2 0.10.9", "sha3", diff --git a/Cargo.toml b/Cargo.toml index e8f14170..4107c046 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } # more openvm related libs -openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.4.0" } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.4.0", default-features = false } sbv-core = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2" } sbv-helpers = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["dev"] } From 8df338c82e4b4ae5d822416cb1228f83c221b744 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Mon, 18 May 2026 21:30:06 +0800 Subject: [PATCH 07/19] update exe commit --- crates/circuits/batch-circuit/batch_exe_commit.rs | 2 +- crates/circuits/bundle-circuit/bundle_exe_commit.rs | 2 +- crates/circuits/chunk-circuit/chunk_exe_commit.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 50f9f957..7992d676 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1941961454, 477170407, 129479363, 346777881, 1960024003, 1085475360, 189100159, 745934103]; +pub const COMMIT: [u32; 8] = [1478427818, 946954232, 316622560, 2007918891, 394494812, 782229538, 478495588, 1982431220]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index def756a5..65541baf 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1881598004, 970250555, 1933976758, 277699807, 1238449309, 1025509899, 1136847759, 777751013]; +pub const COMMIT: [u32; 8] = [830278672, 9058437, 1623618274, 791292874, 1035401947, 1412813097, 214194085, 1529698223]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 3797e753..5ceededa 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [772167398, 274296420, 122391362, 18861170, 1678047186, 1143048180, 1123167759, 1472433101]; +pub const COMMIT: [u32; 8] = [1788988139, 1107313006, 1637036819, 1599849469, 124130784, 890961572, 545684057, 233970417]; From d1abb5e6a6b9587be20293c6139378feeaf8bdbc Mon Sep 17 00:00:00 2001 From: Velaciela Date: Mon, 18 May 2026 22:58:05 +0800 Subject: [PATCH 08/19] exe comm --- crates/circuits/batch-circuit/batch_exe_commit.rs | 2 +- crates/circuits/bundle-circuit/bundle_exe_commit.rs | 2 +- crates/circuits/chunk-circuit/chunk_exe_commit.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 7992d676..f3af61f9 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1478427818, 946954232, 316622560, 2007918891, 394494812, 782229538, 478495588, 1982431220]; +pub const COMMIT: [u32; 8] = [1800656617, 108589020, 1529113621, 298185248, 1253778744, 1797584236, 696805707, 1748169452]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 65541baf..3d2f4af1 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [830278672, 9058437, 1623618274, 791292874, 1035401947, 1412813097, 214194085, 1529698223]; +pub const COMMIT: [u32; 8] = [761206123, 150931274, 967637088, 1698571866, 511050104, 1446730878, 1127595366, 758397854]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 5ceededa..42e8505d 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1788988139, 1107313006, 1637036819, 1599849469, 124130784, 890961572, 545684057, 233970417]; +pub const COMMIT: [u32; 8] = [1125568356, 1145972890, 1198286409, 736377498, 1592430422, 1996972424, 744451071, 299440602]; From 38945183a99a3447e73522b59bddb827ec2a48ed Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sat, 23 May 2026 12:57:56 +0800 Subject: [PATCH 09/19] openvm v2.1 --- AGENTS.md | 67 +- Cargo.lock | 1117 +++++---- Cargo.toml | 62 +- Makefile | 2 +- README.md | 27 +- crates/build-guest/Cargo.toml | 10 +- crates/build-guest/src/main.rs | 259 +- crates/build-guest/src/verifier.rs | 154 +- crates/circuits/batch-circuit/Cargo.toml | 4 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- crates/circuits/batch-circuit/openvm.toml | 2 +- crates/circuits/batch-circuit/src/circuit.rs | 4 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- crates/circuits/chunk-circuit/Cargo.toml | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/circuits/chunk-circuit/openvm.toml | 2 +- crates/circuits/chunk-circuit/src/circuit.rs | 2 +- crates/circuits/chunk-circuit/src/main.rs | 7 +- crates/integration/Cargo.toml | 5 + crates/integration/src/bin/chunk-benchmark.rs | 14 +- crates/integration/src/lib.rs | 189 +- crates/integration/src/testers/batch.rs | 15 +- crates/integration/src/testers/bundle.rs | 22 +- crates/integration/tests/bundle_circuit.rs | 8 +- crates/prover/Cargo.toml | 10 +- crates/prover/src/prover/mod.rs | 255 +- crates/prover/src/setup.rs | 7 +- crates/prover/src/task/mod.rs | 11 +- crates/types/Cargo.toml | 4 +- .../batch/src/blob_consistency/openvm.rs | 5 +- crates/types/chunk/src/crypto.rs | 3 +- crates/types/circuit/Cargo.toml | 2 + crates/types/circuit/src/lib.rs | 74 +- crates/types/src/openvm.rs | 19 +- crates/types/src/proof.rs | 56 +- crates/types/src/task.rs | 3 + crates/types/src/utils.rs | 19 + crates/types/src/zkvm.rs | 14 +- crates/verifier/Cargo.toml | 7 +- crates/verifier/src/evm.rs | 7 +- crates/verifier/src/verifier.rs | 111 +- docs/openvm-v2-migration.md | 229 ++ releases/dev/verifier/verifier.bin | Bin 18558 -> 19405 bytes releases/dev/verifier/verifier.sol | 2233 +---------------- rust-toolchain.toml | 2 +- 48 files changed, 2018 insertions(+), 3039 deletions(-) create mode 100644 docs/openvm-v2-migration.md diff --git a/AGENTS.md b/AGENTS.md index fff655ad..2577aff4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,27 +13,31 @@ Critical context for AI agents working on this repo. Read this before making cha ## OpenVM Version Sensitivity -This project uses **OpenVM** as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: +This project uses **OpenVM v2.0.0-beta.2** as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: - The guest/host data layout (hint streams, public inputs) -- The `root_verifier.asm` format -- The Halo2 SRS degree requirement (e.g. `k=23` → `k=24`) +- The Halo2 SRS degree requirement - The EVM verifier contract ABI -- Field algebra APIs (`from_canonical_u32` → `from_int`) -- ECC constructor signatures (some became `unsafe`) +- Field algebra APIs +- ECC constructor signatures ### After ANY OpenVM version upgrade, you MUST: 1. **Update the hardcoded version string** in `crates/build-guest/src/verifier.rs`: ```rust - let openvm_version = "v1.6"; // MUST match Cargo.toml git rev + let openvm_version = "v2.1.0"; // MUST match openvm-solidity-sdk tag ``` 2. **Force-rebuild ALL guest assets** (auto mode skips existing files): ```bash - cargo run --release -p scroll-zkvm-build-guest -- --mode force + RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest -- --mode force ``` - This regenerates: `app.elf`, `app.vmexe`, `root_verifier.asm`, commitment `.rs` files, and `openVmVk.json`. + This regenerates: `app.elf`, `app.vmexe`, commitment `.rs` files, `openVmVk.json`, + and the EVM verifier (`verifier.sol` + `verifier.bin`). + + > `RECOMPUTE_MODE=yes` is **required** to regenerate the EVM verifier bytecode. + > Without it the build only downloads the Solidity source, producing an empty + > bytecode file that will cause `verify_evm_proof` to fail. 3. **Verify commitments were updated** — check that `*_exe_commit.rs` and `*_vm_commit.rs` files changed, and that `openVmVk.json` timestamps are fresh. @@ -44,8 +48,7 @@ This project uses **OpenVM** as its ZKVM. Guest executables (`.vmexe`) and host These are cached proving keys. They are **not** automatically invalidated on version bumps. 5. **Check SRS params** in `~/.openvm/params/`: - - OpenVM v1.5.0+ requires `kzg_bn254_24.srs` (2 GB) - - Earlier versions used `kzg_bn254_23.srs` (1 GB) + - OpenVM v2 requires `kzg_bn254_24.srs` (2 GB) - If the file is empty/corrupted, replace it (check for `.1` or `.part` suffixes from interrupted downloads) 6. **Clear test output cache** before re-running integration tests: @@ -60,16 +63,28 @@ This project uses **OpenVM** as its ZKVM. Guest executables (`.vmexe`) and host ``` assertion left == right failed (left: 21, right: 1) ``` -**Cause**: Stale guest assets (`app.vmexe` or `root_verifier.asm`) from a previous OpenVM version. +**Cause**: Stale guest assets (`app.vmexe`) from a previous OpenVM version. **Fix**: Follow all 6 steps above. ### `UnexpectedEof` in `CacheHalo2ParamsReader::read_params` ``` UnexpectedEof: failed to fill whole buffer ``` -**Cause**: `~/.openvm/params/kzg_bn254_24.srs` is missing, empty, or truncated. +**Cause**: `~/.openvm/params/kzg_bn254_24.srs` is missing, empty, or truncated. **Fix**: Ensure a valid 2 GB SRS file exists at that exact path. +### `ProofVerificationFailed()` (Solidity error `0xd611c318`) +**Cause**: The EVM verifier was generated with a different circuit config than the proof. +This happens when: +- The verifier was built **without** `RECOMPUTE_MODE=yes` (uses `Sdk::riscv32()` default) +- The verifier was built **without** the deferral prover, but the proof uses deferral (batch/bundle) +- The verifier's `AggregationTreeConfig` does not match the prover's (`num_children_internal/leaf`) + +**Fix**: Regenerate with: +```bash +RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest -- --mode force +``` + ### Docker build fails with stale CID The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. Use local build (`cargo run -p scroll-zkvm-build-guest`) as fallback. @@ -77,12 +92,13 @@ The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. U ```bash # Force rebuild all guest assets (required after OpenVM upgrade) -cargo run --release -p scroll-zkvm-build-guest -- --mode force +RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest -- --mode force # Run end-to-end tests (ALWAYS use make, never raw cargo test) GPU=1 make test-e2e-bundle GPU=1 make test-e2e-batch -GPU=1 make test-e2e-chunk +GPU=1 make test-single-chunk +GPU=1 make test-multi-chunk ``` **⚠️ CRITICAL: Always use `make` for integration tests.** @@ -90,12 +106,33 @@ The Makefile sets `RUST_MIN_STACK=16777216` (16 MB) and `CARGO_CONFIG_FLAG`. Run - Stack overflow during prover initialization (default Rust stack is only ~2 MB) - Missing CUDA features if `GPU=1` is set but `--features scroll-zkvm-integration/cuda` is not passed +## Deferral Model (OpenVM v2+) + +OpenVM v2 replaces the traditional root-verifier recursion with a **deferred compute model**: + +- **Chunk** (leaf circuit, 42 AIRs): no deferral +- **Batch** (aggregation, 44 AIRs): defers child STARK verification to the root +- **Bundle** (aggregation, 44 AIRs): defers child STARK verification to the root + +The extra 2 AIRs in batch/bundle come from the deferral extension. + +### Key configuration that must match between prover and verifier + +| Parameter | Prover (`crates/prover/src/prover/mod.rs`) | Verifier (`crates/build-guest/src/main.rs`) | +|-----------|---------------------------------------------|---------------------------------------------| +| `AggregationTreeConfig` | `num_children_internal: 2, num_children_leaf: 2` | Same | +| `DeferralProver` | Built from child SDK in `enable_deferral()` | Built from batch SDK in `generate_evm_verifier()` | +| `agg_params` | `leaf_params + internal_params` (100-bit security) | Same | + +If any of these mismatch, the EVM verifier will reject proofs with `ProofVerificationFailed()`. + ## Important File Paths | File / Dir | Purpose | |------------|---------| | `releases/dev/{chunk,batch,bundle}/app.vmexe` | Guest executables | | `releases/dev/verifier/openVmVk.json` | Program commitments loaded by integration tests | +| `releases/dev/verifier/verifier.bin` | EVM verifier bytecode | | `crates/circuits/*-circuit/openvm.toml` | Guest VM configs (FRI params, PoW bits) | | `crates/circuits/*-circuit/commitments.rs` | Hardcoded commitment arrays | | `~/.openvm/params/kzg_bn254_24.srs` | Halo2 KZG SRS (2 GB) | @@ -106,4 +143,4 @@ The Makefile sets `RUST_MIN_STACK=16777216` (16 MB) and `CARGO_CONFIG_FLAG`. Run - `chunk-circuit`: requires `system.config.continuation_enabled = true` - `batch-circuit` / `bundle-circuit`: include `leaf_fri_params` with `num_queries = 193`, `commit_proof_of_work_bits = 20` -- FRI params format changed in OpenVM 1.6.0: `proof_of_work_bits` → `commit_proof_of_work_bits` + `query_proof_of_work_bits` +- FRI params format in OpenVM v2: `commit_proof_of_work_bits` + `query_proof_of_work_bits` diff --git a/Cargo.lock b/Cargo.lock index e718fc12..b430518a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -648,7 +648,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", - "winnow", + "winnow 0.7.13", ] [[package]] @@ -800,7 +800,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -811,7 +811,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1303,24 +1303,10 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648bd963d2e5d465377acecfb4b827f9f553b6bc97a8f61715779e9ed9e52b74" dependencies = [ - "arrayvec", - "bitcode_derive", "bytemuck", - "glam", "serde", ] -[[package]] -name = "bitcode_derive" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffebfc2d28a12b262c303cb3860ee77b91bd83b1f20f0bd2a9693008e2f55a9e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - [[package]] name = "bitcoin-io" version = "0.1.3" @@ -1385,19 +1371,6 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "blake3" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -1508,7 +1481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.110", @@ -1712,6 +1685,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.17", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -1991,24 +1973,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "cuda-config" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee74643f7430213a1a78320f88649de309b20b80818325575e393f848f79f5d" -dependencies = [ - "glob", -] - -[[package]] -name = "cuda-runtime-sys" -version = "0.3.0-alpha.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d070b301187fee3c611e75a425cf12247b7c75c09729dbdef95cb9cb64e8c39" -dependencies = [ - "cuda-config", -] - [[package]] name = "cudarc" version = "0.9.15" @@ -2354,6 +2318,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encoder-standard" version = "0.1.0" @@ -2424,7 +2400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2809,12 +2785,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "glam" -version = "0.30.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd47b05dddf0005d850e5644cae7f2b14ac3df487979dbfff3b56f20b1a6ae46" - [[package]] name = "glob" version = "0.3.3" @@ -3096,6 +3066,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" + [[package]] name = "hkdf" version = "0.12.4" @@ -3530,12 +3506,12 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "ecdsa", "elliptic-curve", "ff 0.13.1", - "hex-literal", + "hex-literal 1.1.0", "num-bigint", "once_cell", "openvm", @@ -3713,6 +3689,16 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -3848,6 +3834,21 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -3884,7 +3885,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4022,12 +4023,21 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.110", ] +[[package]] +name = "nvtx" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2e855e8019f99e4b94ac33670eb4e4f570a2e044f3749a0b2c7f83b841e52c" +dependencies = [ + "cc", +] + [[package]] name = "nybbles" version = "0.3.4" @@ -4220,8 +4230,8 @@ dependencies = [ [[package]] name = "openvm" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4235,8 +4245,8 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "blstrs", "cfg-if", @@ -4246,13 +4256,15 @@ dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", "num-traits", + "once_cell", "openvm-algebra-transpiler", + "openvm-algebra-utils", "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", - "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", "openvm-mod-circuit-builder", @@ -4268,8 +4280,8 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-macros-common", "quote", @@ -4278,8 +4290,8 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", @@ -4294,8 +4306,8 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "num-bigint", "num-prime", @@ -4306,8 +4318,8 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-algebra-guest", "openvm-instructions", @@ -4318,52 +4330,57 @@ dependencies = [ "strum 0.26.3", ] +[[package]] +name = "openvm-algebra-utils" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "num-bigint", + "num-traits", + "rand 0.9.4", +] + [[package]] name = "openvm-benchmarks-prove" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "clap", - "derive_more 1.0.0", "eyre", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "metrics", - "openvm-benchmarks-utils", "openvm-circuit", - "openvm-continuations", - "openvm-native-circuit", - "openvm-native-compiler", - "openvm-native-recursion", "openvm-sdk", + "openvm-sdk-config", "openvm-stark-backend", "openvm-stark-sdk", "openvm-transpiler", - "rand 0.9.4", + "openvm-verify-stark-host", + "p3-field", "rand_chacha 0.3.1", "tiny-keccak", - "tokio", "tracing", + "zstd", ] [[package]] name = "openvm-benchmarks-utils" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "cargo_metadata 0.18.1", "clap", "eyre", "openvm-build", "openvm-transpiler", - "tempfile", "tracing", "tracing-subscriber 0.3.20", ] [[package]] name = "openvm-bigint-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4373,6 +4390,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -4388,8 +4406,8 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4397,8 +4415,8 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-bigint-guest", "openvm-instructions", @@ -4412,8 +4430,8 @@ dependencies = [ [[package]] name = "openvm-build" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4424,11 +4442,12 @@ dependencies = [ [[package]] name = "openvm-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "abi_stable", "backtrace", + "bytesize", "cfg-if", "dashmap", "derivative", @@ -4444,6 +4463,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -4464,8 +4484,8 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4475,84 +4495,131 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", "num-bigint", "num-traits", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", "openvm-stark-backend", "rand 0.9.4", + "struct-reflection", "tracing", ] [[package]] name = "openvm-circuit-primitives-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "openvm-codec-derive" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", "quote", "syn 2.0.110", ] [[package]] name = "openvm-continuations" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ - "derivative", + "cfg-if", + "derive-new 0.6.0", + "eyre", + "itertools 0.14.0", + "num-bigint", "openvm-circuit", - "openvm-native-compiler", - "openvm-native-recursion", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-poseidon2-air", + "openvm-recursion-circuit", + "openvm-recursion-circuit-derive", "openvm-stark-backend", "openvm-stark-sdk", + "openvm-verify-stark-host", + "p3-air", "p3-bn254", + "p3-field", + "p3-matrix", + "tracing", +] + +[[package]] +name = "openvm-cpu-backend" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +dependencies = [ + "cfg-if", + "derive-new 0.7.0", + "getset", + "itertools 0.14.0", + "openvm-stark-backend", + "p3-air", + "p3-baby-bear", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "rayon", + "rustc-hash 2.1.1", "serde", - "static_assertions", + "thiserror 1.0.69", + "tracing", ] [[package]] name = "openvm-cuda-backend" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" dependencies = [ - "bincode 2.0.1", - "bincode_derive", - "derivative", "derive-new 0.7.0", + "getset", + "glob", "itertools 0.14.0", - "lazy_static", - "metrics", "openvm-cuda-builder", "openvm-cuda-common", "openvm-stark-backend", "openvm-stark-sdk", "p3-baby-bear", - "p3-commit", + "p3-bn254", "p3-dft", "p3-field", - "p3-fri", - "p3-matrix", - "p3-merkle-tree", "p3-symmetric", "p3-util", + "rand 0.9.4", "rustc-hash 2.1.1", "serde", - "serde_json", "thiserror 1.0.69", "tracing", + "zkhash", ] [[package]] name = "openvm-cuda-builder" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" dependencies = [ "cc", "glob", @@ -4560,8 +4627,8 @@ dependencies = [ [[package]] name = "openvm-cuda-common" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" dependencies = [ "bytesize", "ctor", @@ -4575,24 +4642,83 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "proc-macro2", "quote", "syn 2.0.110", ] +[[package]] +name = "openvm-deferral-circuit" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "cfg-if", + "dashmap", + "derive-new 0.6.0", + "derive_more 1.0.0", + "eyre", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-deferral-transpiler", + "openvm-instructions", + "openvm-poseidon2-air", + "openvm-rv32im-circuit", + "openvm-rv32im-transpiler", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-field", + "rand 0.9.4", + "rustc-hash 2.1.1", + "serde", + "static_assertions", + "strum 0.26.3", +] + +[[package]] +name = "openvm-deferral-guest" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "openvm-custom-insn", + "strum_macros 0.26.4", +] + +[[package]] +name = "openvm-deferral-transpiler" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "eyre", + "openvm-deferral-guest", + "openvm-instructions", + "openvm-instructions-derive", + "openvm-transpiler", + "p3-field", + "rrs-lib", + "serde", + "strum 0.26.3", +] + [[package]] name = "openvm-ecc-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "blstrs", "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "hex-literal", + "hex-literal 1.1.0", "lazy_static", "num-bigint", "num-traits", @@ -4601,6 +4727,7 @@ dependencies = [ "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-common", "openvm-ecc-transpiler", @@ -4617,8 +4744,8 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "ecdsa", "elliptic-curve", @@ -4636,8 +4763,8 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-macros-common", "quote", @@ -4646,8 +4773,8 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-ecc-guest", "openvm-instructions", @@ -4660,8 +4787,8 @@ dependencies = [ [[package]] name = "openvm-instructions" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4677,19 +4804,27 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "quote", "syn 2.0.110", ] +[[package]] +name = "openvm-keccak256" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "openvm-keccak256-guest", + "spin 0.10.0", +] + [[package]] name = "openvm-keccak256-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ - "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "itertools 0.14.0", @@ -4697,6 +4832,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -4714,16 +4850,16 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-platform", ] [[package]] name = "openvm-keccak256-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -4736,26 +4872,22 @@ dependencies = [ [[package]] name = "openvm-macros-common" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "syn 2.0.110", ] [[package]] name = "openvm-mod-circuit-builder" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ - "cuda-runtime-sys", "itertools 0.14.0", "num-bigint", "num-traits", "openvm-circuit", "openvm-circuit-primitives", - "openvm-cuda-backend", - "openvm-cuda-builder", - "openvm-cuda-common", "openvm-instructions", "openvm-stark-backend", "openvm-stark-sdk", @@ -4764,115 +4896,14 @@ dependencies = [ "tracing", ] -[[package]] -name = "openvm-native-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "cfg-if", - "derive-new 0.6.0", - "derive_more 1.0.0", - "eyre", - "itertools 0.14.0", - "openvm-circuit", - "openvm-circuit-derive", - "openvm-circuit-primitives", - "openvm-circuit-primitives-derive", - "openvm-cuda-backend", - "openvm-cuda-builder", - "openvm-cuda-common", - "openvm-instructions", - "openvm-native-compiler", - "openvm-poseidon2-air", - "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", - "openvm-stark-backend", - "openvm-stark-sdk", - "p3-field", - "rand 0.9.4", - "serde", - "static_assertions", - "strum 0.26.3", -] - -[[package]] -name = "openvm-native-compiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "backtrace", - "itertools 0.14.0", - "num-bigint", - "num-integer", - "openvm-circuit", - "openvm-instructions", - "openvm-instructions-derive", - "openvm-native-compiler-derive", - "openvm-rv32im-transpiler", - "openvm-stark-backend", - "openvm-stark-sdk", - "serde", - "snark-verifier-sdk", - "strum 0.26.3", - "strum_macros 0.26.4", - "zkhash", -] - -[[package]] -name = "openvm-native-compiler-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "quote", - "syn 2.0.110", -] - -[[package]] -name = "openvm-native-recursion" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "cfg-if", - "itertools 0.14.0", - "lazy_static", - "once_cell", - "openvm-circuit", - "openvm-native-circuit", - "openvm-native-compiler", - "openvm-native-compiler-derive", - "openvm-stark-backend", - "openvm-stark-sdk", - "p3-dft", - "p3-fri", - "p3-merkle-tree", - "p3-symmetric", - "rand 0.8.6", - "rand 0.9.4", - "serde", - "serde_json", - "serde_with", - "snark-verifier-sdk", - "tracing", -] - -[[package]] -name = "openvm-native-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "openvm-instructions", - "openvm-transpiler", - "p3-field", -] - [[package]] name = "openvm-pairing" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "hex-literal", + "hex-literal 1.1.0", "itertools 0.14.0", "num-bigint", "num-traits", @@ -4891,8 +4922,8 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4905,6 +4936,7 @@ dependencies = [ "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-ecc-circuit", "openvm-ecc-guest", @@ -4922,12 +4954,12 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "hex-literal", + "hex-literal 1.1.0", "itertools 0.14.0", "lazy_static", "num-bigint", @@ -4943,8 +4975,8 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-instructions", "openvm-pairing-guest", @@ -4956,8 +4988,8 @@ dependencies = [ [[package]] name = "openvm-platform" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "libm", "openvm-custom-insn", @@ -4966,11 +4998,12 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "derivative", "lazy_static", + "openvm-circuit-primitives", "openvm-cuda-builder", "openvm-stark-backend", "openvm-stark-sdk", @@ -4981,10 +5014,48 @@ dependencies = [ "zkhash", ] +[[package]] +name = "openvm-recursion-circuit" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "derive-new 0.6.0", + "eyre", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-poseidon2-air", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-air", + "p3-baby-bear", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "strum 0.26.3", + "strum_macros 0.26.4", + "tracing", +] + +[[package]] +name = "openvm-recursion-circuit-derive" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "quote", + "syn 2.0.110", +] + [[package]] name = "openvm-rv32-adapters" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5000,8 +5071,8 @@ dependencies = [ [[package]] name = "openvm-rv32im-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5013,6 +5084,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -5027,8 +5099,8 @@ dependencies = [ [[package]] name = "openvm-rv32im-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-custom-insn", "p3-field", @@ -5037,8 +5109,8 @@ dependencies = [ [[package]] name = "openvm-rv32im-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5053,124 +5125,150 @@ dependencies = [ [[package]] name = "openvm-sdk" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ + "alloy-sol-types", "bitcode", "bon", "cfg-if", "clap", "derivative", + "derive-new 0.6.0", "derive_more 1.0.0", "eyre", "getset", + "halo2-base", "hex", "itertools 0.14.0", - "metrics", "num-bigint", "openvm", + "openvm-build", + "openvm-circuit", + "openvm-continuations", + "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-recursion-circuit", + "openvm-sdk-config", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-transpiler", + "openvm-verify-stark-host", + "p3-bn254", + "serde", + "serde_json", + "serde_with", + "tempfile", + "thiserror 1.0.69", + "toml", + "tracing", +] + +[[package]] +name = "openvm-sdk-config" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "bon", + "cfg-if", + "derive_more 1.0.0", + "openvm", "openvm-algebra-circuit", "openvm-algebra-transpiler", "openvm-bigint-circuit", "openvm-bigint-transpiler", - "openvm-build", "openvm-circuit", - "openvm-continuations", + "openvm-cpu-backend", "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-deferral-transpiler", "openvm-ecc-circuit", "openvm-ecc-transpiler", "openvm-keccak256-circuit", "openvm-keccak256-transpiler", - "openvm-native-circuit", - "openvm-native-compiler", - "openvm-native-recursion", - "openvm-native-transpiler", "openvm-pairing-circuit", "openvm-pairing-transpiler", "openvm-rv32im-circuit", "openvm-rv32im-transpiler", - "openvm-sha256-circuit", - "openvm-sha256-transpiler", + "openvm-sha2-circuit", + "openvm-sha2-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "openvm-transpiler", - "p3-bn254", - "p3-fri", - "rand 0.9.4", - "rrs-lib", "serde", - "serde_json", - "serde_with", - "snark-verifier", - "snark-verifier-sdk", - "tempfile", - "thiserror 1.0.69", "toml", - "tracing", ] [[package]] name = "openvm-sha2" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ - "openvm-sha256-guest", + "openvm", + "openvm-sha2-guest", "sha2 0.10.9", ] [[package]] -name = "openvm-sha256-air" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-air" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ + "ndarray", + "num_enum", "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", "openvm-stark-backend", "rand 0.9.4", "sha2 0.10.9", ] [[package]] -name = "openvm-sha256-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-circuit" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", + "itertools 0.14.0", + "ndarray", "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", "openvm-rv32im-circuit", - "openvm-sha256-air", - "openvm-sha256-transpiler", + "openvm-sha2-air", + "openvm-sha2-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", "serde", "sha2 0.10.9", - "strum 0.26.3", ] [[package]] -name = "openvm-sha256-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-guest" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-platform", ] [[package]] -name = "openvm-sha256-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-transpiler" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "openvm-instructions", "openvm-instructions-derive", - "openvm-sha256-guest", + "openvm-sha2-guest", "openvm-stark-backend", "openvm-transpiler", "rrs-lib", @@ -5179,23 +5277,29 @@ dependencies = [ [[package]] name = "openvm-stark-backend" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" dependencies = [ - "bitcode", "cfg-if", "derivative", "derive-new 0.7.0", "eyre", + "getset", + "hex-literal 1.1.0", "itertools 0.14.0", "metrics", + "num-bigint", + "openvm-codec-derive", "p3-air", "p3-challenger", - "p3-commit", + "p3-dft", "p3-field", + "p3-interpolation", "p3-matrix", "p3-maybe-rayon", + "p3-symmetric", "p3-util", + "postcard", "rayon", "rustc-hash 2.1.1", "serde", @@ -5206,46 +5310,63 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0-alpha" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" dependencies = [ "dashmap", - "derivative", - "derive_more 1.0.0", - "ff 0.13.1", + "derive-new 0.7.0", + "eyre", + "hex-literal 1.1.0", "itertools 0.14.0", "metrics", "metrics-tracing-context", "metrics-util", "num-bigint", + "nvtx", + "openvm-cpu-backend", "openvm-stark-backend", "p3-baby-bear", - "p3-blake3", "p3-bn254", - "p3-dft", - "p3-fri", - "p3-goldilocks", - "p3-keccak", - "p3-koala-bear", - "p3-merkle-tree", - "p3-poseidon", + "p3-field", "p3-poseidon2", - "p3-symmetric", "rand 0.9.4", "serde", "serde_json", "static_assertions", - "toml", "tracing", "tracing-forest", "tracing-subscriber 0.3.20", "zkhash", ] +[[package]] +name = "openvm-static-verifier" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "halo2-base", + "itertools 0.14.0", + "num-bigint", + "num-integer", + "once_cell", + "openvm-circuit-primitives-derive", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-recursion-circuit", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "serde_with", + "snark-verifier-sdk", + "tracing", +] + [[package]] name = "openvm-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "elf", "eyre", @@ -5257,6 +5378,62 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "openvm-verify-stark-circuit" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "cfg-if", + "derive-new 0.6.0", + "eyre", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-deferral-circuit", + "openvm-poseidon2-air", + "openvm-recursion-circuit", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "p3-air", + "p3-bn254", + "p3-field", + "p3-matrix", + "tracing", +] + +[[package]] +name = "openvm-verify-stark-guest" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "openvm-deferral-guest", +] + +[[package]] +name = "openvm-verify-stark-host" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +dependencies = [ + "bitcode", + "eyre", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-field", + "serde", + "thiserror 1.0.69", + "zstd", +] + [[package]] name = "ordered-float" version = "4.6.0" @@ -5281,12 +5458,12 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" dependencies = [ "ecdsa", "elliptic-curve", "ff 0.13.1", - "hex-literal", + "hex-literal 1.1.0", "num-bigint", "openvm", "openvm-algebra-guest", @@ -5321,17 +5498,6 @@ dependencies = [ "rand 0.9.4", ] -[[package]] -name = "p3-blake3" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8f97fd783752532861bf29bac344b7c226a0d1e2151148834c43c651a5d401" -dependencies = [ - "blake3", - "p3-symmetric", - "p3-util", -] - [[package]] name = "p3-bn254" version = "0.4.3" @@ -5362,21 +5528,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-commit" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6d7dcb58a8f21f0e1325dc7f7699ad749878ccbe7e286e61f9d46bde2bfa88" -dependencies = [ - "itertools 0.14.0", - "p3-challenger", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-util", - "serde", -] - [[package]] name = "p3-dft" version = "0.4.3" @@ -5408,46 +5559,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-fri" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13ca6a795cfc4180425fbf16dfdb4c9c2bfa85971dd55b5930d97b513e0835df" -dependencies = [ - "itertools 0.14.0", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-interpolation", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", - "rand 0.9.4", - "serde", - "thiserror 2.0.17", - "tracing", -] - -[[package]] -name = "p3-goldilocks" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c47d5c650bbeb25941b9a1fa9bfaf59b3cd202a438ea2c20892489af001399" -dependencies = [ - "num-bigint", - "p3-challenger", - "p3-dft", - "p3-field", - "p3-mds", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "paste", - "rand 0.9.4", - "serde", -] - [[package]] name = "p3-interpolation" version = "0.4.3" @@ -5460,18 +5571,6 @@ dependencies = [ "p3-util", ] -[[package]] -name = "p3-keccak" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61b090fb42152d1fcb2f82227b8619b1b022f9cd4a123123dccc9c2ab75d5de" -dependencies = [ - "p3-field", - "p3-symmetric", - "p3-util", - "tiny-keccak", -] - [[package]] name = "p3-keccak-air" version = "0.4.3" @@ -5487,20 +5586,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-koala-bear" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb02789fca0950e246123d652bd78e75a76e3b90a651fd88dbb215cd3e81f5a" -dependencies = [ - "p3-challenger", - "p3-field", - "p3-monty-31", - "p3-poseidon2", - "p3-symmetric", - "rand 0.9.4", -] - [[package]] name = "p3-matrix" version = "0.4.3" @@ -5538,25 +5623,6 @@ dependencies = [ "rand 0.9.4", ] -[[package]] -name = "p3-merkle-tree" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e20f61ea816e94f83ed7b8134a5e98d0cad7bd6dff226bc1da17a5143c63cb" -dependencies = [ - "itertools 0.14.0", - "p3-commit", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", - "rand 0.9.4", - "serde", - "thiserror 2.0.17", - "tracing", -] - [[package]] name = "p3-monty-31" version = "0.4.3" @@ -5580,18 +5646,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-poseidon" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548af7ff569975882bc411f653aba7d89a6d85813ca58ef922fd0b1ecb6b5866" -dependencies = [ - "p3-field", - "p3-mds", - "p3-symmetric", - "rand 0.9.4", -] - [[package]] name = "p3-poseidon2" version = "0.4.3" @@ -5681,7 +5735,7 @@ version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.110", @@ -5913,6 +5967,15 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "poseidon-primitives" version = "0.2.0" @@ -5928,6 +5991,18 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -5982,6 +6057,16 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -6192,6 +6277,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.11.0" @@ -7713,7 +7804,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -7959,9 +8050,9 @@ dependencies = [ "openvm", "openvm-algebra-guest", "openvm-ecc-guest", - "openvm-keccak256-guest", + "openvm-keccak256", "openvm-pairing", - "openvm-sha256-guest", + "openvm-sha2-guest", "scroll-zkvm-types-batch", "scroll-zkvm-types-circuit", ] @@ -7976,11 +8067,15 @@ dependencies = [ "eyre", "hex", "openvm-build", + "openvm-circuit", + "openvm-continuations", + "openvm-deferral-circuit", "openvm-instructions", - "openvm-native-compiler", - "openvm-native-recursion", "openvm-sdk", + "openvm-sdk-config", "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-circuit", "scroll-zkvm-types", "serde_json", "snark-verifier-sdk", @@ -8005,18 +8100,18 @@ version = "0.7.1" dependencies = [ "bincode 2.0.1", "ecies", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", "openvm", "openvm-algebra-complex-macros", "openvm-algebra-guest", "openvm-bigint-guest", "openvm-ecc-guest", - "openvm-keccak256-guest", + "openvm-keccak256", "openvm-pairing", "openvm-pairing-guest", "openvm-rv32im-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", "scroll-zkvm-types-chunk", "scroll-zkvm-types-circuit", ] @@ -8047,6 +8142,10 @@ dependencies = [ "openvm-benchmarks-utils", "openvm-circuit", "openvm-sdk", + "openvm-sdk-config", + "openvm-stark-sdk", + "openvm-verify-stark-circuit", + "openvm-verify-stark-host", "rayon", "regex", "revm 29.0.1", @@ -8061,6 +8160,7 @@ dependencies = [ "snark-verifier-sdk", "sysinfo", "tokio", + "toml", "tracing", "tracing-subscriber 0.3.20", "url", @@ -8078,10 +8178,14 @@ dependencies = [ "git-version", "hex", "openvm-circuit", - "openvm-native-circuit", - "openvm-native-recursion", + "openvm-cuda-backend", + "openvm-deferral-circuit", "openvm-sdk", + "openvm-sdk-config", "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-circuit", + "openvm-verify-stark-host", "scroll-zkvm-types", "scroll-zkvm-verifier", "serde", @@ -8102,9 +8206,11 @@ dependencies = [ "eyre", "hex", "once_cell", - "openvm-native-recursion", + "openvm-circuit", "openvm-sdk", "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-host", "sbv-primitives", "scroll-zkvm-types-base", "scroll-zkvm-types-batch", @@ -8166,14 +8272,14 @@ dependencies = [ "ark-ff 0.5.0", "ark-serialize 0.5.0", "ecies", - "hex-literal", + "hex-literal 0.4.1", "itertools 0.14.0", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", "openvm-ecc-guest", "openvm-pairing", "openvm-pairing-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", "sbv-core", "sbv-helpers", "sbv-primitives", @@ -8191,7 +8297,9 @@ dependencies = [ "itertools 0.14.0", "openvm", "openvm-custom-insn", + "openvm-deferral-guest", "openvm-rv32im-guest", + "openvm-verify-stark-guest", "scroll-zkvm-types-base", ] @@ -8202,9 +8310,12 @@ dependencies = [ "bincode 1.3.3", "eyre", "once_cell", + "openvm-circuit", "openvm-continuations", - "openvm-native-recursion", "openvm-sdk", + "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-host", "scroll-zkvm-types", "serde", "serde_json", @@ -8706,6 +8817,26 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "struct-reflection" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "701b671d1ad68e250e05718f95dae3014a17f4e69cbe51842531c30495ff3301" +dependencies = [ + "struct-reflection-derive", +] + +[[package]] +name = "struct-reflection-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ab74230a0592602e361bd63c645413fa8cbe4500d10274e849179e5c72548f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "strum" version = "0.25.0" @@ -8858,7 +8989,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -9095,6 +9226,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.12.0", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -9106,7 +9248,7 @@ dependencies = [ "serde_spanned", "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.13", ] [[package]] @@ -9118,7 +9260,7 @@ dependencies = [ "indexmap 2.12.0", "toml_datetime 0.7.3", "toml_parser", - "winnow", + "winnow 0.7.13", ] [[package]] @@ -9127,7 +9269,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow", + "winnow 0.7.13", ] [[package]] @@ -9863,6 +10005,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.7.13" diff --git a/Cargo.toml b/Cargo.toml index 4107c046..3cca58ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,47 +26,53 @@ version = "0.8.0" [workspace.dependencies] # openvm guest libs -openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0" } -openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0" } -openvm-sha256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", package = "p256", features = [ +openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr" } +openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr" } +openvm-sha2-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", package = "p256", features = [ "std", ] } -openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", package = "k256", features = [ +openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", package = "k256", features = [ "std", ] } -openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0" } -openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr" } +openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } # openvm host libs -openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-build = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-native-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-native-compiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-native-recursion = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-native-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } -openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false, features = [ +openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-build = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-static-verifier = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-verify-stark-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } +openvm-deferral-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false, features = [ "parallel", "evm-prove", "tco", "unprotected" ] } -openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.6.0", default-features = false } +openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } # more openvm related libs -openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.4.0", default-features = false } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } sbv-core = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2" } sbv-helpers = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["dev"] } diff --git a/Makefile b/Makefile index 1c021d89..b3e0fff1 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ export RUST_BACKTRACE RUST_LOG ?= off,scroll_zkvm_integration=debug,scroll_zkvm_verifier=debug,scroll_zkvm_prover=debug,p3_fri=warn,p3_dft=warn,openvm_circuit=warn export RUST_LOG -OPENVM_RUST_TOOLCHAIN ?= nightly-2025-08-18 +OPENVM_RUST_TOOLCHAIN ?= nightly-2025-11-20 export OPENVM_RUST_TOOLCHAIN # Set GPU config if GPU=1 is set diff --git a/README.md b/README.md index 09bc08e5..d726608d 100644 --- a/README.md +++ b/README.md @@ -26,20 +26,33 @@ The [prover](./crates/prover) crate offers a minimalistic API for setting up, ge For a deeper dive into our implementation, please refer the [interfaces](./docs/interfaces.md) doc. -## Testing - -For more commands please refer the [Makefile](./Makefile). - -### Build Guest Programs +## Build Guest Programs -In case you have made any changes to the guest programs, it is important to build them before running the tests. +In case you have made any changes to the guest programs, or after upgrading OpenVM, +it is important to rebuild them before running the tests. ```shell +# Standard rebuild (skips existing artifacts) $ make build-guest + +# Force full rebuild — required after OpenVM upgrades +$ RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest -- --mode force ``` +> `RECOMPUTE_MODE=yes` tells `build-guest` to regenerate the EVM verifier **bytecode** +> from scratch instead of downloading only the Solidity source. Without this, +> EVM proof verification will fail because `verifier.bin` will be empty. + Upon building the guest programs, the child commitments in [batch-circuit](./crates/circuits/batch-circuit/src/child_commitments.rs) and [bundle-circuit](./crates/circuits/bundle-circuit/src/child_commitments.rs) will be overwritten by `build-guest`. +## Testing + +For more commands please refer the [Makefile](./Makefile). + +### Build Guest Programs + +In case you have made any changes to the guest programs, it is important to build them before running the tests. + ### End-to-end tests for chunk-prover ```shell @@ -78,7 +91,7 @@ Add the following dependency in your `Cargo.toml`: ```toml [dependencies] -scroll-zkvm-prover = { git = "https://github.com/scroll-tech/zkvm-prover", branch = "master" } +scroll-zkvm-prover = { git = "https://github.com/scroll-tech/zkvm-prover", branch = "develop-v2.1.0-rvr" } ``` ### To prove a universal task with STARK proofs diff --git a/crates/build-guest/Cargo.toml b/crates/build-guest/Cargo.toml index 6acba274..fc00af7a 100644 --- a/crates/build-guest/Cargo.toml +++ b/crates/build-guest/Cargo.toml @@ -6,12 +6,16 @@ edition.workspace = true [dependencies] scroll-zkvm-types.workspace = true +openvm-continuations.workspace = true openvm-instructions.workspace = true -openvm-native-compiler.workspace = true -openvm-native-recursion.workspace = true -openvm-sdk.workspace = true +openvm-sdk = { workspace = true, features = ["evm-verify"] } +openvm-sdk-config = { workspace = true } +openvm-static-verifier = { workspace = true } openvm-stark-sdk.workspace = true openvm-build = { workspace = true, default-features = false } +openvm-circuit.workspace = true +openvm-deferral-circuit.workspace = true +openvm-verify-stark-circuit.workspace = true eyre.workspace = true hex.workspace = true serde_json.workspace = true diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index e381e0e2..ea3a5625 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -10,8 +10,7 @@ //! 4. Creates verification keys and supporting files //! //! ## OpenVM Assets Generation: -//! 1. Generates root verifier assembly code -//! 2. Creates EVM verifier contract (Solidity) and bytecode +//! 1. Generates EVM verifier contract (Solidity) and bytecode //! //! ## Usage: //! ```bash @@ -24,7 +23,7 @@ //! - `force`: Always regenerate all files (use for clean builds or CI) //! //! ## Environment Variables: -//! - `BUILD_PROJECT`: Comma-separated list of projects to build (e.g., "chunk,batch"). +//! - `BUILD_PROJECT`: Comma-separated list of projects to build (e.g. "chunk,batch"). //! Defaults to "chunk,batch,bundle". //! //! ## Output: @@ -37,19 +36,27 @@ use dotenvy::dotenv; use eyre::Result; use openvm_build::GuestOptions; use openvm_instructions::exe::VmExe; -use openvm_native_compiler::ir::DIGEST_SIZE; +use openvm_circuit::arch::instructions::DEFERRAL_AS; use openvm_sdk::{ F, Sdk, - commit::CommitBytes, - config::{AppConfig, SdkVmConfig}, + config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}, fs::write_object_to_file, - prover::AppProver, + prover::DeferralProver, }; +use openvm_sdk_config::SdkVmConfig; use openvm_stark_sdk::{ - openvm_stark_backend::p3_field::RawDataSerializable, p3_bn254::Bn254 as Bn254Fr, + config::{app_params_with_100_bits_security, internal_params_with_100_bits_security, leaf_params_with_100_bits_security, root_params_with_100_bits_security}, + openvm_stark_backend::p3_field::PrimeField32, }; +use openvm_continuations::CommitBytes; +use openvm_deferral_circuit::DeferralFn; +use openvm_verify_stark_circuit::extension::verify_stark_deferral_fn; +use openvm_verify_stark_circuit::prover::{ + DeferredVerifyCpuCircuitProver as VerifyCircuitProver, + DeferredVerifyCpuProver as VerifyProver, +}; +use openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine as DeferralEngine; use scroll_zkvm_types::zkvm::AGG_STARK_PROVING_KEY; -use snark_verifier_sdk::snark_verifier::loader::evm::compile_solidity; use std::{ env, fs, path::{Path, PathBuf}, @@ -59,6 +66,16 @@ use std::{ mod verifier; +const DIGEST_SIZE: usize = 8; + +/// Default aggregation parameters used across chunk, batch, and bundle circuits. +fn default_agg_params() -> AggregationSystemParams { + AggregationSystemParams { + leaf: leaf_params_with_100_bits_security(), + internal: internal_params_with_100_bits_security(), + } +} + #[derive(Debug, Clone, ValueEnum)] enum OutputMode { /// Skip generation when output file already exists (default) @@ -107,22 +124,43 @@ fn write_commitment_as_evm_hex( output_path: &PathBuf, commitment: [u32; DIGEST_SIZE], ) -> Result<()> { - let digest_bytes = compress_commitment(&commitment) - .into_bytes() - .into_iter() - .rev() // To big endian - .collect::>(); + let commit_bytes = CommitBytes::from(commitment); if let Some(parent) = output_path.parent() { fs::create_dir_all(parent)?; } - fs::write(output_path, hex::encode(digest_bytes))?; + fs::write(output_path, hex::encode(commit_bytes.as_slice()))?; println!("{LOG_PREFIX} Wrote commitment to {}", output_path.display()); Ok(()) } -/// Compresses an 8-element u32 commitment into a single Fr element. -/// Used for generating digests compatible with on-chain verifiers. -fn compress_commitment(commitment: &[u32; DIGEST_SIZE]) -> Bn254Fr { - CommitBytes::from_u32_digest(commitment).to_bn254() + +/// Build a DeferralProver from a child SDK (CPU-only; build-guest does not use cuda). +fn make_deferral_prover(sdk: &Sdk, agg_params: &AggregationSystemParams) -> DeferralProver { + let agg_prover = sdk.agg_prover(); + let ir_vk = agg_prover.internal_recursive_prover.get_vk(); + let ir_pcs_data = agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .expect("missing child VK PCS data"); + let system_config = sdk.app_config().app_vm_config.as_ref().clone(); + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + let def_circuit_params = internal_params_with_100_bits_security(); + let child_def_hook_commit = sdk.def_hook_commit(); + let deferred_verify_prover = VerifyProver::new::( + ir_vk.clone(), + ir_pcs_data.commitment.into(), + def_circuit_params, + memory_dimensions, + num_user_pvs, + child_def_hook_commit, + 0, + ); + let verify_stark_prover = VerifyCircuitProver::new(deferred_verify_prover); + let hook_params = root_params_with_100_bits_security(); + let agg_config = AggregationConfig { + params: agg_params.clone(), + }; + DeferralProver::new(verify_stark_prover, agg_config, hook_params) } /// Builds guest programs, transpiles them, and generates executable commitments. @@ -138,7 +176,12 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re println!("{LOG_PREFIX} Projects to build: {:?}", projects_to_build); + let _app_params = app_params_with_100_bits_security(21); + let agg_params = default_agg_params(); + let mut vk_dump: serde_json::Value = serde_json::from_str("{}")?; + let mut prev_sdk: Option = None; + for project_name in projects_to_build { let project_path = workspace_dir .join("crates") @@ -153,20 +196,46 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re let project_dir = project_path.to_str().expect("Invalid path"); // First read the app config specified in the project's root directory. let path_app_config = Path::new(project_dir).join(FD_APP_CONFIG); - let app_config: AppConfig = + let mut app_config: AppConfig = toml::from_str(&fs::read_to_string(&path_app_config)?)?; println!( "{project_dir} app config: {}", toml::to_string_pretty(&app_config)? ); - // copy path_app_config as ${release_output_dir}/${project_name}/${FD_APP_CONFIG} + // Enable deferral for aggregation circuits using the previous SDK + let deferral_prover: Option = if (project_name == "batch" || project_name == "bundle") + && prev_sdk.is_some() + { + let child_sdk = prev_sdk.as_ref().unwrap(); + let deferral_prover = make_deferral_prover(child_sdk, &agg_params); + let deferral_ext = deferral_prover + .make_extension(vec![Arc::new(DeferralFn::new(verify_stark_deferral_fn))]); + app_config.app_vm_config.deferral = Some(deferral_ext); + app_config.app_vm_config.system.config.memory_config.addr_spaces + [DEFERRAL_AS as usize] + .num_cells = 1 << 25; + Some(deferral_prover) + } else { + None + }; + + // Write config (possibly modified with deferral) to release output dir let output_path = release_output_dir.join(project_name).join(FD_APP_CONFIG); if let Some(parent) = output_path.parent() { fs::create_dir_all(parent)?; } - fs::copy(&path_app_config, &output_path)?; - println!("{LOG_PREFIX} Copied config to {}", output_path.display()); + fs::write(&output_path, toml::to_string_pretty(&app_config)?)?; + println!("{LOG_PREFIX} Wrote config to {}", output_path.display()); + + // Build SDK with the project-specific app config + let mut sdk_builder = Sdk::builder() + .app_config(app_config.clone()) + .agg_params(agg_params.clone()); + if let Some(dp) = deferral_prover { + sdk_builder = sdk_builder.deferral_prover(dp); + } + let sdk = sdk_builder.build()?; // 1. Build ELF @@ -186,7 +255,6 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re ..Default::default() }; let guest_opts = guest_opts.with_profile("maxperf".to_string()); - let sdk = Sdk::new(app_config)?; let elf = sdk .build(guest_opts, project_dir, &Default::default(), None) .inspect_err(|_err| { @@ -222,16 +290,11 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re println!("{LOG_PREFIX} exe written to {path_app_exe:?}"); // 3. Compute and Write Executable Commitment - let app_pk = sdk.app_pk(); - let app_prover: AppProver = AppProver::new( - *sdk.app_vm_builder(), - &app_pk.app_vm_pk, - Arc::new(app_exe), - app_pk.leaf_committed_exe.get_program_commit(), - )?; - let app_comm = app_prover.app_commit(); - let exe_commit_u32 = app_comm.app_exe_commit.to_u32_digest(); - let vm_commit_u32 = app_comm.app_vm_commit.to_u32_digest(); + let prover = sdk.prover(Arc::new(app_exe.clone()))?; + let exe_digest = prover.app_prover.app_exe_commit(); + let vm_digest = prover.app_vm_commit(); + let exe_commit_u32: [u32; DIGEST_SIZE] = std::array::from_fn(|i| exe_digest[i].as_canonical_u32()); + let vm_commit_u32: [u32; DIGEST_SIZE] = std::array::from_fn(|i| vm_digest[i].as_canonical_u32()); write_commitment( &Path::new(project_dir).join(format!("{project_name}_exe_commit.rs")), @@ -265,6 +328,8 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re "{LOG_PREFIX} Finished build for config in {:?}", start_time.elapsed() ); + + prev_sdk = Some(sdk); } let output_path = release_output_dir.join("verifier").join("openVmVk.json"); @@ -281,53 +346,59 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re Ok(()) } -/// Generates the root verifier assembly code. -fn generate_root_verifier(workspace_dir: &Path, force_overwrite: bool) -> Result<()> { - println!("{LOG_PREFIX} === Generating Root Verifier Assembly ==="); - - let root_verifier_path = workspace_dir - .join("crates") - .join("build-guest") - .join("root_verifier.asm"); - - // Check if file exists and skip if in auto mode - if !force_overwrite && root_verifier_path.exists() { - println!( - "{LOG_PREFIX} Root verifier already exists, skipping (use --output-mode force to overwrite)" - ); - return Ok(()); - } - - let asm = Sdk::riscv32().generate_root_verifier_asm(); - fs::write(&root_verifier_path, asm).expect("fail to write"); - - println!( - "{LOG_PREFIX} Root verifier generated at: {}", - root_verifier_path.display() - ); - +/// Root verifier assembly is no longer needed in v2 (deferred compute model). +fn generate_root_verifier(_workspace_dir: &Path, _force_overwrite: bool) -> Result<()> { + println!("{LOG_PREFIX} === Root Verifier Assembly ==="); + println!("{LOG_PREFIX} Skipping: root verifier ASM is deprecated in OpenVM v2"); Ok(()) } +/// Default aggregation-tree shape used by the host prover and the EVM verifier. +/// +/// Must stay in sync with [`Prover::get_sdk`](crates/prover/src/prover/mod.rs). +const DEFAULT_AGG_TREE_CONFIG: AggregationTreeConfig = AggregationTreeConfig { + num_children_internal: 2, + num_children_leaf: 2, +}; + +/// Generate the EVM verifier Solidity contract and its deployment bytecode. +/// +/// # Modes +/// +/// ## `RECOMPUTE_MODE=yes` (recommended for releases) +/// Re-generates the verifier from scratch using the local OpenVM SDK. +/// This requires: +/// 1. Building a **batch SDK** to obtain the deferral prover (matches host prover config). +/// 2. Loading the **bundle app config** so the verifier hardcodes the same aggregation-tree +/// shape and deferral settings as the bundle circuit. +/// +/// ## Download mode (default) +/// Downloads a pre-built Solidity verifier from `openvm-solidity-sdk`. +/// No bytecode is produced; only the `.sol` file is fetched. fn generate_evm_verifier( + _workspace_dir: &Path, + release_output_dir: &PathBuf, verifier_output_dir: &PathBuf, recompute_mode: bool, force_overwrite: bool, ) -> Result<()> { - println!("{LOG_PREFIX} === Dumping EVM VERIFIER ==="); + println!("{LOG_PREFIX} === Generating EVM Verifier ==="); let path_verifier_sol = verifier_output_dir.join("verifier.sol"); let path_verifier_bin = verifier_output_dir.join("verifier.bin"); let path_root_agg_pk = verifier_output_dir.join("root_verifier_vk"); if force_overwrite || !path_root_agg_pk.exists() { - write_object_to_file(&path_root_agg_pk, AGG_STARK_PROVING_KEY.get_agg_vk()) - .expect("fail to write"); + write_object_to_file( + &path_root_agg_pk, + AGG_STARK_PROVING_KEY.internal_recursive.get_vk().clone(), + ) + .expect("failed to write root_verifier_vk"); } - // Check if files exist and skip if in auto mode + // Skip regeneration in auto mode when artifacts already exist. if !force_overwrite && path_verifier_sol.exists() && path_verifier_bin.exists() { println!( - "{LOG_PREFIX} EVM verifier files already exist, skipping (use --output-mode force to overwrite)" + "{LOG_PREFIX} EVM verifier files already exist, skipping (use --mode force to overwrite)" ); return Ok(()); } @@ -336,16 +407,59 @@ fn generate_evm_verifier( fs::create_dir_all(parent)?; } - let verifier_sol = if recompute_mode { - verifier::generate_evm_verifier()? + let app_params = app_params_with_100_bits_security(21); + let agg_params = default_agg_params(); + + if !recompute_mode { + println!( + "{LOG_PREFIX} WARNING: RECOMPUTE_MODE is not set. The EVM verifier will be downloaded \ + from openvm-solidity-sdk, which currently does not publish a v2-compatible verifier. \ + verifier.bin will be EMPTY and EVM proof verification will fail. \ + Run with RECOMPUTE_MODE=yes to generate the verifier locally." + ); + } + + let sdk = if recompute_mode { + // 1. Build a batch SDK to create a DeferralProver that matches the host prover. + let batch_config_path = release_output_dir.join("batch").join(FD_APP_CONFIG); + let batch_app_config: AppConfig = if batch_config_path.exists() { + toml::from_str(&fs::read_to_string(&batch_config_path)?)? + } else { + AppConfig::riscv32(app_params.clone()) + }; + let batch_sdk = Sdk::builder() + .app_config(batch_app_config) + .agg_params(agg_params.clone()) + .build()?; + let deferral_prover = make_deferral_prover(&batch_sdk, &agg_params); + + // 2. Load the bundle config so the verifier matches the bundle circuit's + // aggregation-tree shape and deferral settings. + let bundle_config_path = release_output_dir.join("bundle").join(FD_APP_CONFIG); + let bundle_app_config: AppConfig = if bundle_config_path.exists() { + toml::from_str(&fs::read_to_string(&bundle_config_path)?)? + } else { + AppConfig::riscv32(app_params.clone()) + }; + Sdk::builder() + .app_config(bundle_app_config) + .agg_params(agg_params) + .agg_tree_config(DEFAULT_AGG_TREE_CONFIG) + .deferral_prover(deferral_prover) + .build()? + } else { + Sdk::riscv32(app_params, agg_params) + }; + + let verifier = if recompute_mode { + sdk.generate_halo2_verifier_solidity()? } else { verifier::download_evm_verifier()? }; - fs::write(&path_verifier_sol, &verifier_sol)?; + fs::write(&path_verifier_sol, &verifier.openvm_verifier_code)?; println!("{LOG_PREFIX} verifier_sol written to {path_verifier_sol:?}"); - let verifier_bin = compile_solidity(&verifier_sol); - fs::write(&path_verifier_bin, &verifier_bin)?; + fs::write(&path_verifier_bin, &verifier.artifact.bytecode)?; println!("{LOG_PREFIX} verifier_bin written to {path_verifier_bin:?}"); Ok(()) @@ -362,6 +476,8 @@ fn generate_openvm_assets( generate_root_verifier(workspace_dir, force_overwrite)?; let recompute_mode = env::var("RECOMPUTE_MODE").is_ok_and(|value| value == "yes"); generate_evm_verifier( + workspace_dir, + release_output_dir, &release_output_dir.join("verifier"), recompute_mode, force_overwrite, @@ -397,11 +513,12 @@ pub fn main() -> Result<()> { println!("{LOG_PREFIX} Generating openvm assets"); let force_overwrite = matches!(cli.mode, OutputMode::Force); - generate_openvm_assets(&workspace_dir, &release_output_dir, force_overwrite)?; - println!("{LOG_PREFIX} Generating app assets (always overwrite)"); generate_app_assets(&workspace_dir, &release_output_dir)?; + println!("{LOG_PREFIX} Generating openvm assets"); + generate_openvm_assets(&workspace_dir, &release_output_dir, force_overwrite)?; + println!("{LOG_PREFIX} Build process completed successfully."); Ok(()) } diff --git a/crates/build-guest/src/verifier.rs b/crates/build-guest/src/verifier.rs index ba8dbcb2..f1bbc738 100644 --- a/crates/build-guest/src/verifier.rs +++ b/crates/build-guest/src/verifier.rs @@ -1,127 +1,91 @@ use super::LOG_PREFIX; use eyre::Result; -use openvm_native_recursion::halo2::utils::Halo2ParamsReader; -use openvm_sdk::Sdk; -use snark_verifier_sdk::SHPLONK; -pub fn generate_evm_verifier() -> Result { - let sdk = Sdk::riscv32(); - let halo2_params_reader = sdk.halo2_params_reader(); - let halo2_pk = sdk.halo2_pk(); - let halo2_params = - halo2_params_reader.read_params(halo2_pk.wrapper.pinning.metadata.config_params.k); - let sol_code = snark_verifier_sdk::evm::gen_evm_verifier_sol_code::< - snark_verifier_sdk::halo2::aggregation::AggregationCircuit, - SHPLONK, - >( - &halo2_params, - halo2_pk.wrapper.pinning.pk.get_vk(), - halo2_pk.wrapper.pinning.metadata.num_pvs.clone(), - ); - - // 1. write sol_code to a tmp file - // 2. use `forge fmt $tmpfile` to format it - // 3. read it out again, and assign the String as `sol_code` - let temp_file = std::env::temp_dir().join("Halo2Verifier.sol"); - std::fs::write(&temp_file, &sol_code)?; - - let format_output = std::process::Command::new("forge") - .arg("fmt") - .arg(&temp_file) - .output(); - - let sol_code = match format_output { - Ok(output) if output.status.success() => { - println!("{LOG_PREFIX} Formatted verifier with forge fmt"); - std::fs::read_to_string(&temp_file)? - } - _ => { - println!("{LOG_PREFIX} Warning: forge fmt failed, using unformatted code"); - sol_code - } - }; - - // Clean up temp file - let _ = std::fs::remove_file(&temp_file); - - Ok(sol_code) -} - -pub fn download_evm_verifier() -> Result { - let openvm_version = "v1.6"; +/// Download a pre-built Solidity verifier from `openvm-solidity-sdk`. +/// +/// # Note +/// The version string below tracks the **solidity-sdk** release tag, not the +/// `openvm` crate version. Keep it in sync with the `openvm-solidity-sdk` +/// revision used by the pinned `openvm` crates. +pub fn download_evm_verifier() -> Result { + let openvm_version = "v2.1.0"; let verifier_url = format!( - "https://github.com/openvm-org/openvm-solidity-sdk/raw/refs/heads/main/src/{openvm_version}/Halo2Verifier.sol" + "https://github.com/openvm-org/openvm-solidity-sdk/raw/refs/heads/main/src/{openvm_version}/OpenVmHalo2Verifier.sol" + ); + let interface_url = format!( + "https://github.com/openvm-org/openvm-solidity-sdk/raw/refs/heads/main/src/{openvm_version}/IOpenVmHalo2Verifier.sol" ); println!("{LOG_PREFIX} Downloading pre-built verifier from openvm-solidity-sdk..."); - let output = std::process::Command::new("wget") + let sol_output = std::process::Command::new("wget") .arg("-q") .arg("-O") .arg("-") .arg(&verifier_url) .output()?; - if !output.status.success() { + if !sol_output.status.success() { return Err(eyre::eyre!( "Failed to download verifier from {}: wget exited with code {:?}", verifier_url, - output.status.code() + sol_output.status.code() )); } - println!("{LOG_PREFIX} Downloaded Halo2Verifier.sol"); + let interface_output = std::process::Command::new("wget") + .arg("-q") + .arg("-O") + .arg("-") + .arg(&interface_url) + .output()?; - let sol_code = String::from_utf8(output.stdout)?; + if !interface_output.status.success() { + return Err(eyre::eyre!( + "Failed to download interface from {}: wget exited with code {:?}", + interface_url, + interface_output.status.code() + )); + } - Ok(sol_code) + println!("{LOG_PREFIX} Downloaded OpenVmHalo2Verifier.sol"); + + // In download mode we don't have bytecode, return empty artifact + let sol_code = String::from_utf8(sol_output.stdout)?; + let interface_code = String::from_utf8(interface_output.stdout)?; + + Ok(openvm_sdk::types::EvmHalo2Verifier { + halo2_verifier_code: String::new(), + openvm_verifier_code: sol_code, + openvm_verifier_interface: interface_code, + artifact: openvm_static_verifier::wrapper::EvmVerifierByteCode { + sol_compiler_version: String::new(), + sol_compiler_options: String::new(), + bytecode: Vec::new(), + }, + }) } #[cfg(test)] mod tests { use super::*; - use std::fs; - #[test] + #[ignore = "requires openvm-solidity-sdk to publish v2 verifier (currently unavailable)"] fn test_verifier() { - // assert `generate_evm_verifier` vs `download_evm_verifier` result are equal - // if not, dump them to 2 files, and let user use vimdiff to check - - let num_preview_lines = 10; - let print_verifier_info = |name: &str, code: &str| { - println!("{} verifier length: {} bytes", name, code.len()); - let lines: Vec<&str> = code.lines().collect(); - for line in lines.iter().take(num_preview_lines) { - println!("{}", line); - } - println!("..."); - for line in lines.iter().rev().take(num_preview_lines).rev() { - println!("{}", line); - } - }; + // Smoke-test: ensure the download URL is still reachable and returns + // non-empty Solidity code. A full "generate vs download" comparison + // requires a full SDK setup and is exercised in CI instead. + // + // Note: As of OpenVM v2.0.0-beta.2, the solidity-sdk repo only has + // v1.x tags. Use RECOMPUTE_MODE=yes to generate the verifier locally. let downloaded = download_evm_verifier().expect("Failed to download EVM verifier"); - print_verifier_info("Downloaded", &downloaded); - - let generated = generate_evm_verifier().expect("Failed to generate EVM verifier"); - print_verifier_info("Generated", &generated); - - if generated != downloaded { - let temp_dir = std::env::temp_dir(); - let generated_file = temp_dir.join("generated_verifier.sol"); - let downloaded_file = temp_dir.join("downloaded_verifier.sol"); - - fs::write(&generated_file, &generated).expect("Failed to write generated verifier"); - fs::write(&downloaded_file, &downloaded).expect("Failed to write downloaded verifier"); - - panic!( - "Verifiers are different! Compare files:\n Generated: {}\n Downloaded: {}\nUse: vimdiff {} {}", - generated_file.display(), - downloaded_file.display(), - generated_file.display(), - downloaded_file.display() - ); - } else { - println!("Verifiers match successfully!"); - } + assert!( + !downloaded.openvm_verifier_code.is_empty(), + "downloaded verifier code is empty" + ); + println!( + "Downloaded verifier length: {} bytes", + downloaded.openvm_verifier_code.len() + ); } } diff --git a/crates/circuits/batch-circuit/Cargo.toml b/crates/circuits/batch-circuit/Cargo.toml index ee7a8082..f2090725 100644 --- a/crates/circuits/batch-circuit/Cargo.toml +++ b/crates/circuits/batch-circuit/Cargo.toml @@ -12,8 +12,8 @@ scroll-zkvm-types-batch.workspace = true openvm = { workspace = true, features = ["std"] } openvm-algebra-guest.workspace = true openvm-pairing = { workspace = true, features = ["bls12_381"] } -openvm-keccak256-guest.workspace = true -openvm-sha256-guest.workspace = true +openvm-keccak256 = { workspace = true } +openvm-sha2-guest.workspace = true openvm-ecc-guest = { workspace = true, features = ["halo2curves"] } alloy-primitives = { workspace = true, features = ["native-keccak"] } diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index f3af61f9..cd9d8ccf 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1800656617, 108589020, 1529113621, 298185248, 1253778744, 1797584236, 696805707, 1748169452]; +pub const COMMIT: [u32; 8] = [520116242, 438206942, 1460585682, 1080375955, 655525982, 291819449, 289597192, 739536847]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 73b57247..3d972af1 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1792226047, 611100767, 1146270814, 1810005845, 1491201797, 1214999763, 783504632, 1498168266]; +pub const COMMIT: [u32; 8] = [1585746298, 1227330313, 377026605, 1453044393, 1602011240, 557491268, 632299533, 1648695606]; diff --git a/crates/circuits/batch-circuit/openvm.toml b/crates/circuits/batch-circuit/openvm.toml index 57f20c6d..a309c5b2 100644 --- a/crates/circuits/batch-circuit/openvm.toml +++ b/crates/circuits/batch-circuit/openvm.toml @@ -23,7 +23,7 @@ supported_moduli = [ [app_vm_config.native] [app_vm_config.pairing] supported_curves = ["Bls12_381"] -[app_vm_config.sha256] +[app_vm_config.sha2] [app_vm_config.fp2] supported_moduli = [ ["Bls12_381Fp2","4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"] diff --git a/crates/circuits/batch-circuit/src/circuit.rs b/crates/circuits/batch-circuit/src/circuit.rs index 83a24da4..bae66db0 100644 --- a/crates/circuits/batch-circuit/src/circuit.rs +++ b/crates/circuits/batch-circuit/src/circuit.rs @@ -18,9 +18,9 @@ use crate::child_commitments; use { openvm_algebra_guest::{IntMod, field::FieldExtension}, openvm_ecc_guest::AffinePoint, - openvm_keccak256_guest, // trigger extern native-keccak256 + openvm_keccak256, // trigger extern native-keccak256 openvm_pairing::bls12_381::{Bls12_381, Bls12_381G1Affine, Fp, Fp2}, - openvm_sha256_guest, + openvm_sha2_guest, }; openvm::init!(); diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 3d2f4af1..edefc4f4 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [761206123, 150931274, 967637088, 1698571866, 511050104, 1446730878, 1127595366, 758397854]; +pub const COMMIT: [u32; 8] = [1136275893, 1407154518, 920919977, 364816368, 1499414199, 1138007052, 1783034630, 977110994]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index e346add1..3bb595a6 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [925169990, 1379116760, 1021966620, 1957896599, 611090420, 136189529, 1819023587, 441111398]; +pub const COMMIT: [u32; 8] = [1268707915, 137202277, 1407567349, 1777716679, 18254191, 1760215902, 572689567, 1219299492]; diff --git a/crates/circuits/chunk-circuit/Cargo.toml b/crates/circuits/chunk-circuit/Cargo.toml index 122b2150..28a21f3f 100644 --- a/crates/circuits/chunk-circuit/Cargo.toml +++ b/crates/circuits/chunk-circuit/Cargo.toml @@ -19,7 +19,7 @@ openvm-algebra-complex-macros = { workspace = true } openvm-algebra-guest = { workspace = true } openvm-bigint-guest = { workspace = true } openvm-ecc-guest = { workspace = true } -openvm-keccak256-guest= { workspace = true } +openvm-keccak256 = { workspace = true } openvm-pairing-guest = { workspace = true, features = ["bn254"] } openvm-sha2 = { workspace = true } openvm-rv32im-guest= { workspace = true } diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 42e8505d..7da902af 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1125568356, 1145972890, 1198286409, 736377498, 1592430422, 1996972424, 744451071, 299440602]; +pub const COMMIT: [u32; 8] = [1735893845, 1221356996, 1546836896, 1762308944, 160310189, 2004482779, 1193790493, 1139072554]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index 2de70f52..7a23999e 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1467589762, 470654227, 683360028, 597448633, 205292274, 1767305327, 1252880894, 241340940]; +pub const COMMIT: [u32; 8] = [1367261305, 1725314385, 56774325, 974516987, 645567438, 1297433976, 1574497560, 1739847365]; diff --git a/crates/circuits/chunk-circuit/openvm.toml b/crates/circuits/chunk-circuit/openvm.toml index b7caf215..9ddc457b 100644 --- a/crates/circuits/chunk-circuit/openvm.toml +++ b/crates/circuits/chunk-circuit/openvm.toml @@ -35,7 +35,7 @@ supported_moduli = [ [app_vm_config.pairing] supported_curves = ["Bn254"] -[app_vm_config.sha256] +[app_vm_config.sha2] [[app_vm_config.ecc.supported_curves]] struct_name = "Secp256k1Point" diff --git a/crates/circuits/chunk-circuit/src/circuit.rs b/crates/circuits/chunk-circuit/src/circuit.rs index 366ad5cb..51d23693 100644 --- a/crates/circuits/chunk-circuit/src/circuit.rs +++ b/crates/circuits/chunk-circuit/src/circuit.rs @@ -15,7 +15,7 @@ use { openvm_algebra_guest::IntMod, openvm_bigint_guest, // trigger extern u256 (this may be unneeded) openvm_k256::Secp256k1Point, - openvm_keccak256_guest, // trigger extern native-keccak256 + openvm_keccak256, // trigger extern native-keccak256 openvm_p256::P256Point, openvm_pairing::bn254::Bn254G1Affine, }; diff --git a/crates/circuits/chunk-circuit/src/main.rs b/crates/circuits/chunk-circuit/src/main.rs index 2e521cd2..58fd6d7a 100644 --- a/crates/circuits/chunk-circuit/src/main.rs +++ b/crates/circuits/chunk-circuit/src/main.rs @@ -6,12 +6,17 @@ use circuit::ChunkCircuit as C; openvm::entry!(main); +fn sha256_digest(input: &[u8], output: &mut [u8; 32]) { + use openvm_sha2::Digest; + *output = openvm_sha2::Sha256::digest(input).into(); +} + fn main() { Crypto::install(); ecies::sha256::set_digest_provider(|| { Box::new(ecies::sha256::ext::ExtSha256Core::new( - openvm_sha2::set_sha256, + sha256_digest, )) }) .unwrap(); diff --git a/crates/integration/Cargo.toml b/crates/integration/Cargo.toml index 179d701e..a9d7fff0 100644 --- a/crates/integration/Cargo.toml +++ b/crates/integration/Cargo.toml @@ -26,6 +26,10 @@ openvm-benchmarks-prove = { workspace = true, default-features = false } openvm-benchmarks-utils = { workspace = true, default-features = false } openvm-circuit.workspace = true openvm-sdk = { workspace = true, default-features = false } +openvm-sdk-config = { workspace = true } +openvm-stark-sdk = { workspace = true, default-features = false } +openvm-verify-stark-circuit = { workspace = true, default-features = false } +openvm-verify-stark-host = { workspace = true, default-features = false } alloy-provider = { workspace = true } alloy-rpc-client.workspace = true @@ -49,6 +53,7 @@ glob = "0.3" once_cell = "1.20" revm = { workspace = true } serde_json = "1.0" +toml.workspace = true snark-verifier-sdk = { workspace = true, default-features = false, features = [ "loader_halo2", "halo2-axiom", diff --git a/crates/integration/src/bin/chunk-benchmark.rs b/crates/integration/src/bin/chunk-benchmark.rs index 2e9f6ce4..619ad2f6 100644 --- a/crates/integration/src/bin/chunk-benchmark.rs +++ b/crates/integration/src/bin/chunk-benchmark.rs @@ -1,10 +1,9 @@ #![feature(exit_status_error)] //! Run `make bench-execute-chunk` to execute this benchmark. use clap::Parser; -use openvm_benchmarks_prove::util::BenchmarkCli; +use openvm_benchmarks_prove::BenchmarkCli; use openvm_benchmarks_utils::build_elf; -use openvm_circuit::openvm_stark_sdk::bench::run_with_metric_collection; -use openvm_sdk::config::{SdkVmBuilder, SdkVmConfig}; +use openvm_stark_sdk::bench::run_with_metric_collection; use scroll_zkvm_integration::testers::chunk::{ ChunkProverTester, get_witness_from_env_or_builder, preset_chunk, }; @@ -26,9 +25,9 @@ fn main() -> eyre::Result<()> { let args: BenchmarkCli = BenchmarkCli::parse(); - let app_vm_config = - SdkVmConfig::from_toml(include_str!("../../../circuits/chunk-circuit/openvm.toml"))? - .app_vm_config; + let app_config: openvm_sdk::config::AppConfig = + toml::from_str(include_str!("../../../circuits/chunk-circuit/openvm.toml"))?; + let app_vm_config = app_config.app_vm_config; let project_path = WORKSPACE_ROOT .join("crates") @@ -49,8 +48,7 @@ fn main() -> eyre::Result<()> { let wit = get_witness_from_env_or_builder(&mut preset_chunk())?; run_with_metric_collection("OUTPUT_PATH", || { - args.bench_from_exe::( - "chunk-circuit", + args.run( app_vm_config, elf, ChunkProverTester::build_guest_input(&wit, std::iter::empty())?, diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 51d20842..c85de0dd 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -1,6 +1,10 @@ use cargo_metadata::MetadataCommand; use once_cell::sync::OnceCell; -use openvm_sdk::{Sdk, StdIn}; +use openvm_circuit::arch::deferral::DeferralState; +use openvm_sdk::{DeferralInput, Sdk, StdIn}; +use openvm_stark_sdk::openvm_stark_backend::codec::Decode; +use openvm_verify_stark_circuit::extension::{get_deferral_state, get_raw_deferral_results}; +use openvm_verify_stark_host::{vk::VmStarkVerifyingKey, VmStarkProof}; use scroll_zkvm_prover::{ Prover, setup::{read_app_config, read_app_exe}, @@ -16,6 +20,7 @@ use scroll_zkvm_types::{ use scroll_zkvm_verifier::verifier::{AGG_STARK_PROVING_KEY, UniversalVerifier}; use std::collections::HashMap; use std::{ + io::Cursor, path::{Path, PathBuf}, process, sync::LazyLock, @@ -210,6 +215,7 @@ pub trait ProverTester { fn build_universal_task<'a>( witness: &Self::Witness, aggregated_proofs: impl Iterator, + input_commits: Vec<[u8; 32]>, ) -> eyre::Result { Ok(UniversalProvingTask { serialized_witness: vec![witness.archive()?], @@ -217,6 +223,7 @@ pub trait ProverTester { fork_name: witness.fork_name().as_str().to_string(), identifier: witness.identifier(), vk: Default::default(), + input_commits, }) } @@ -225,14 +232,27 @@ pub trait ProverTester { aggregated_proofs: impl Iterator, ) -> eyre::Result { use scroll_zkvm_prover::task::ProvingTask; - Ok(Self::build_universal_task(witness, aggregated_proofs)?.build_guest_input()) + Ok(Self::build_universal_task(witness, aggregated_proofs, vec![])?.build_guest_input()) } } pub trait TaskProver { fn name(&self) -> &str; fn prove_task(&mut self, t: &UniversalProvingTask, gen_snark: bool) -> eyre::Result; + fn prove_task_with_deferral( + &mut self, + t: &UniversalProvingTask, + gen_snark: bool, + def_inputs: &[DeferralInput], + def_states: &[DeferralState], + ) -> eyre::Result { + // Default: ignore deferral inputs for backward compatibility. + let _ = def_inputs; + let _ = def_states; + self.prove_task(t, gen_snark) + } fn get_vk(&mut self) -> eyre::Result>; + fn get_agg_vk(&self) -> eyre::Result>; } impl TaskProver for Prover { @@ -245,9 +265,27 @@ impl TaskProver for Prover { let stdin = t.build_guest_input(); if !gen_snark { // gen stark proof - Ok(self.gen_proof_stark(stdin)?.into()) + Ok(self.gen_proof_stark(stdin, &[])?.into()) + } else { + let proof: EvmProof = self.gen_proof_snark(stdin, &[])?.into(); + Ok(proof.into()) + } + } + + fn prove_task_with_deferral( + &mut self, + t: &UniversalProvingTask, + gen_snark: bool, + def_inputs: &[DeferralInput], + def_states: &[DeferralState], + ) -> eyre::Result { + use scroll_zkvm_prover::task::ProvingTask; + let mut stdin = t.build_guest_input(); + stdin.deferrals = def_states.to_vec(); + if !gen_snark { + Ok(self.gen_proof_stark(stdin, def_inputs)?.into()) } else { - let proof: EvmProof = self.gen_proof_snark(stdin)?.into(); + let proof: EvmProof = self.gen_proof_snark(stdin, def_inputs)?.into(); Ok(proof.into()) } } @@ -255,6 +293,10 @@ impl TaskProver for Prover { fn get_vk(&mut self) -> eyre::Result> { Ok(self.get_app_vk()) } + + fn get_agg_vk(&self) -> eyre::Result> { + Ok((*self.sdk()?.agg_vk()).clone()) + } } /// Enviroment settings for test: fork dir @@ -333,7 +375,11 @@ pub fn tester_execute( )?; let app_vm_config = app_config.app_vm_config.clone(); - let sdk = Sdk::new(app_config)?; + let sdk = Sdk::builder() + .app_config(app_config) + .agg_pk(AGG_STARK_PROVING_KEY.clone()) + .build() + .map_err(|e| eyre::eyre!("sdk build failed: {e}"))?; let ret = scroll_zkvm_prover::utils::vm::execute_guest( &sdk, app_vm_config.as_ref(), @@ -343,12 +389,82 @@ pub fn tester_execute( Ok(ret) } +/// Decode a [`StarkProof`] into a [`VmStarkProof`]. +fn decode_stark_proof(proof: &StarkProof) -> eyre::Result { + use openvm_circuit::system::memory::merkle::public_values::UserPublicValuesProof; + + let inner = openvm_stark_sdk::openvm_stark_backend::proof::Proof::decode_from_bytes(&proof.proof) + .map_err(|e| eyre::eyre!("decode proof failed: {e}"))?; + let user_pvs_proof = + UserPublicValuesProof::decode::(&mut Cursor::new(&proof.user_pvs_proof)) + .map_err(|e| eyre::eyre!("decode user_pvs_proof failed: {e}"))?; + let deferral_merkle_proofs = if proof.deferral_merkle_proofs.is_empty() { + None + } else { + Some(openvm_verify_stark_host::deferral::DeferralMerkleProofs::decode( + &mut Cursor::new(&proof.deferral_merkle_proofs), + ).map_err(|e| eyre::eyre!("decode deferral_merkle_proofs failed: {e}"))?) + }; + Ok(VmStarkProof { + inner, + user_pvs_proof, + deferral_merkle_proofs, + }) +} + +/// Compute deferral inputs and states from child proofs. +pub fn compute_deferral_data( + child_prover: &Prover, + proofs: &[&StarkProof], +) -> eyre::Result<(Vec<[u8; 32]>, Vec, Vec)> { + let sdk = child_prover + .sdk() + .map_err(|e| eyre::eyre!("failed to get child sdk: {e}"))?; + let mvk = (*sdk.agg_vk()).clone(); + let stark_prover = sdk + .prover(child_prover.app_exe.clone()) + .map_err(|e| eyre::eyre!("failed to create stark prover: {e}"))?; + let baseline = stark_prover.generate_baseline(); + let vk = VmStarkVerifyingKey { mvk, baseline }; + + let vm_proofs: Vec = proofs + .iter() + .map(|p| decode_stark_proof(p)) + .collect::>>()?; + + let raw_results = get_raw_deferral_results(&vk, &vm_proofs) + .map_err(|e| eyre::eyre!("get_raw_deferral_results failed: {e}"))?; + + let input_commits: Vec<[u8; 32]> = raw_results + .iter() + .map(|r| r.input.as_slice().try_into().expect("input commit must be 32 bytes")) + .collect(); + + let deferral_inputs = vec![DeferralInput::from_inputs(&vm_proofs)]; + + let deferral_state = get_deferral_state(&vk, &vm_proofs, 0) + .map_err(|e| eyre::eyre!("get_deferral_state failed: {e}"))?; + + Ok((input_commits, deferral_inputs, vec![deferral_state])) +} + /// End-to-end test for proving witnesses of the same prover. #[instrument(name = "prove_verify", skip_all, fields(task_id, prover_name = prover.name()))] pub fn prove_verify( prover: &mut impl TaskProver, witness: &T::Witness, proofs: &[ProofEnum], +) -> eyre::Result { + prove_verify_with_deferral::(prover, witness, proofs, None) +} + +/// End-to-end test with deferred STARK verification (v2). +#[instrument(name = "prove_verify_with_deferral", skip_all, fields(task_id, prover_name = prover.name()))] +pub fn prove_verify_with_deferral( + prover: &mut impl TaskProver, + witness: &T::Witness, + proofs: &[ProofEnum], + child_prover: Option<&Prover>, ) -> eyre::Result { // Setup prover. let cache_dir = DIR_TESTRUN @@ -369,23 +485,38 @@ pub fn prove_verify( tracing::debug!(name: "early_return_proof", ?task_id); proof } else { + let stark_proofs: Vec<&StarkProof> = proofs + .iter() + .map(|p| p.as_stark_proof().expect("must be stark proof")) + .collect(); + + let (input_commits, def_inputs, def_states) = if let Some(child) = child_prover { + compute_deferral_data(child, &stark_proofs)? + } else { + (vec![], vec![], vec![]) + }; + let task = T::build_universal_task( witness, - proofs - .iter() - .map(|p| p.as_stark_proof().expect("must be stark proof")), + stark_proofs.into_iter(), + input_commits, )?; // Construct stark proof for the circuit. - let proof = prover.prove_task(&task, false)?; + let proof = if def_inputs.is_empty() { + prover.prove_task(&task, false)? + } else { + prover.prove_task_with_deferral(&task, false, &def_inputs, &def_states)? + }; write_json(&path_proof, &proof)?; tracing::debug!(name: "cached_proof", ?task_id); proof }; - // Verify proof. + // Verify proof using the prover's own aggregation VK (required for deferral-enabled circuits). + let agg_vk = prover.get_agg_vk()?; UniversalVerifier::verify_stark_proof_with_vk( - &AGG_STARK_PROVING_KEY.get_agg_vk(), + &agg_vk, proof.as_stark_proof().expect("should be stark proof"), &vk, )?; @@ -400,6 +531,20 @@ pub fn prove_verify_single_evm( witness: &T::Witness, proofs: &[ProofEnum], ) -> eyre::Result +where + T: ProverTester, +{ + prove_verify_single_evm_with_deferral::(prover, witness, proofs, None) +} + +/// End-to-end EVM proof with deferred STARK verification (v2). +#[instrument(name = "prove_verify_single_evm_with_deferral", skip_all)] +pub fn prove_verify_single_evm_with_deferral( + prover: &mut impl TaskProver, + witness: &T::Witness, + proofs: &[ProofEnum], + child_prover: Option<&Prover>, +) -> eyre::Result where T: ProverTester, { @@ -425,14 +570,28 @@ where tracing::debug!(name: "early_return_evm_proof", ?task_id); proof } else { + let stark_proofs: Vec<&StarkProof> = proofs + .iter() + .map(|p| p.as_stark_proof().expect("must be stark proof")) + .collect(); + + let (input_commits, def_inputs, def_states) = if let Some(child) = child_prover { + compute_deferral_data(child, &stark_proofs)? + } else { + (vec![], vec![], vec![]) + }; + let task = T::build_universal_task( witness, - proofs - .iter() - .map(|p| p.as_stark_proof().expect("must be stark proof")), + stark_proofs.into_iter(), + input_commits, )?; // Construct stark proof for the circuit. - let proof = prover.prove_task(&task, true)?; + let proof = if def_inputs.is_empty() { + prover.prove_task(&task, true)? + } else { + prover.prove_task_with_deferral(&task, true, &def_inputs, &def_states)? + }; write_json(&path_proof, &proof)?; tracing::debug!(name: "cached_evm_proof", ?task_id); proof diff --git a/crates/integration/src/testers/batch.rs b/crates/integration/src/testers/batch.rs index f0f9d19f..4628af48 100644 --- a/crates/integration/src/testers/batch.rs +++ b/crates/integration/src/testers/batch.rs @@ -9,10 +9,11 @@ use scroll_zkvm_types::{ }; use crate::{ - PROGRAM_COMMITMENTS, PartialProvingTask, ProverTester, TaskProver, prove_verify, + PROGRAM_COMMITMENTS, PartialProvingTask, ProverTester, TaskProver, prove_verify_with_deferral, testers::chunk::{ChunkTaskGenerator, preset_chunk_multiple, preset_chunk_validium}, utils::{build_batch_witnesses, build_batch_witnesses_validium}, }; +use scroll_zkvm_prover::Prover; impl PartialProvingTask for BatchWitness { fn identifier(&self) -> String { @@ -74,15 +75,21 @@ impl BatchTaskGenerator { pub fn get_or_build_proof( &mut self, - prover: &mut impl TaskProver, - child_prover: &mut impl TaskProver, + prover: &mut Prover, + child_prover: &mut Prover, ) -> eyre::Result { if let Some(proof) = &self.proof { return Ok(proof.clone()); } let wit = self.get_or_build_witness()?; let agg_proofs = self.get_or_build_child_proofs(child_prover)?; - let proof = prove_verify::(prover, &wit, &agg_proofs)?; + prover.enable_deferral(child_prover)?; + let proof = prove_verify_with_deferral::( + prover, + &wit, + &agg_proofs, + Some(child_prover), + )?; self.proof.replace(proof.clone()); Ok(proof) } diff --git a/crates/integration/src/testers/bundle.rs b/crates/integration/src/testers/bundle.rs index eb1bf7ab..9451e406 100644 --- a/crates/integration/src/testers/bundle.rs +++ b/crates/integration/src/testers/bundle.rs @@ -9,9 +9,11 @@ use scroll_zkvm_types::{ // Only related to hardcoded commitments. Can be refactored later. use crate::{ - PROGRAM_COMMITMENTS, PartialProvingTask, ProverTester, TaskProver, prove_verify_single_evm, + PROGRAM_COMMITMENTS, PartialProvingTask, ProverTester, + prove_verify_single_evm_with_deferral, testers::batch::BatchTaskGenerator, utils::metadata_from_batch_witnesses, }; +use scroll_zkvm_prover::Prover; impl PartialProvingTask for BundleWitness { fn identifier(&self) -> String { @@ -60,24 +62,30 @@ impl BundleTaskGenerator { pub fn get_or_build_proof( &mut self, - prover: &mut impl TaskProver, - batch_prover: &mut impl TaskProver, - chunk_prover: &mut impl TaskProver, + prover: &mut Prover, + batch_prover: &mut Prover, + chunk_prover: &mut Prover, ) -> eyre::Result { if let Some(proof) = &self.proof { return Ok(proof.clone()); } let wit = self.get_or_build_witness()?; let agg_proofs = self.get_or_build_child_proofs(batch_prover, chunk_prover)?; - let proof = prove_verify_single_evm::(prover, &wit, &agg_proofs)?; + prover.enable_deferral(batch_prover)?; + let proof = prove_verify_single_evm_with_deferral::( + prover, + &wit, + &agg_proofs, + Some(batch_prover), + )?; self.proof.replace(proof.clone()); Ok(proof) } fn get_or_build_child_proofs( &mut self, - batch_prover: &mut impl TaskProver, - chunk_prover: &mut impl TaskProver, + batch_prover: &mut Prover, + chunk_prover: &mut Prover, ) -> eyre::Result> { let mut proofs = Vec::new(); for chunk_gen in &mut self.batch_generators { diff --git a/crates/integration/tests/bundle_circuit.rs b/crates/integration/tests/bundle_circuit.rs index b44d4887..8d1b582c 100644 --- a/crates/integration/tests/bundle_circuit.rs +++ b/crates/integration/tests/bundle_circuit.rs @@ -1,6 +1,6 @@ use sbv_primitives::B256; use scroll_zkvm_integration::{ - ProverTester, TaskProver, + ProverTester, testers::{ batch::{BatchProverTester, preset_batch_multiple, preset_batch_validium}, bundle::{BundleProverTester, BundleTaskGenerator}, @@ -134,9 +134,9 @@ fn e2e() -> eyre::Result<()> { } fn e2e_inner( - chunk_prover: &mut impl TaskProver, - batch_prover: &mut impl TaskProver, - bundle_prover: &mut impl TaskProver, + chunk_prover: &mut Prover, + batch_prover: &mut Prover, + bundle_prover: &mut Prover, ) -> eyre::Result<()> { let mut task = preset_bundle(); let wit = task.get_or_build_witness()?; diff --git a/crates/prover/Cargo.toml b/crates/prover/Cargo.toml index e7328670..d1dd4f4c 100644 --- a/crates/prover/Cargo.toml +++ b/crates/prover/Cargo.toml @@ -12,10 +12,14 @@ scroll-zkvm-verifier.workspace = true bincode_v1.workspace = true tracing.workspace = true openvm-circuit = { workspace = true } -openvm-native-circuit = { workspace = true, default-features = false } -openvm-native-recursion = { workspace = true } openvm-sdk = { workspace = true } +openvm-sdk-config = { workspace = true } +openvm-static-verifier = { workspace = true } +openvm-deferral-circuit = { workspace = true } +openvm-verify-stark-circuit = { workspace = true } +openvm-verify-stark-host = { workspace = true } openvm-stark-sdk = { workspace = true, default-features = false } +openvm-cuda-backend = { workspace = true, optional = true } base64 = "0.22" eyre.workspace = true @@ -33,6 +37,6 @@ cudarc = { version = "0.9", optional = true } [features] default = [] -cuda = ["openvm-sdk/cuda", "dep:cudarc"] +cuda = ["openvm-sdk/cuda", "dep:cudarc", "openvm-verify-stark-circuit/cuda", "dep:openvm-cuda-backend"] diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index e243a1d6..c5244594 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -3,27 +3,57 @@ use std::{ sync::{Arc, OnceLock}, }; -#[cfg(not(feature = "cuda"))] -use openvm_native_circuit::NativeCpuBuilder as NativeBuilder; -#[cfg(feature = "cuda")] -use openvm_native_circuit::NativeGpuBuilder as NativeBuilder; - -use openvm_circuit::arch::instructions::exe::VmExe; -use openvm_sdk::{DefaultStarkEngine, config::SdkVmBuilder}; -use openvm_sdk::{ - F, Sdk, StdIn, - config::{AppConfig, SdkVmConfig}, - prover::StarkProver, +use openvm_circuit::arch::instructions::{exe::VmExe, DEFERRAL_AS}; +use openvm_sdk::{F, Sdk, StdIn, SC}; +use openvm_sdk::config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}; +use openvm_sdk_config::SdkVmConfig; +use openvm_stark_sdk::{ + config::{internal_params_with_100_bits_security, leaf_params_with_100_bits_security, root_params_with_100_bits_security}, + openvm_stark_backend::{codec::Encode, p3_field::PrimeField32}, }; use scroll_zkvm_types::{proof::OpenVmEvmProof, types_agg::ProgramCommitment, utils::serialize_vk}; -use scroll_zkvm_verifier::verifier::{AGG_STARK_PROVING_KEY, UniversalVerifier}; +use scroll_zkvm_verifier::verifier::UniversalVerifier; use tracing::instrument; +use openvm_deferral_circuit::DeferralFn; +use openvm_sdk::prover::DeferralProver; +use openvm_verify_stark_circuit::extension::verify_stark_deferral_fn; + +#[cfg(feature = "cuda")] +use openvm_cuda_backend::BabyBearPoseidon2GpuEngine as DeferralEngine; +#[cfg(feature = "cuda")] +use openvm_verify_stark_circuit::prover::DeferredVerifyGpuProver as VerifyProver; +#[cfg(feature = "cuda")] +use openvm_verify_stark_circuit::prover::DeferredVerifyGpuCircuitProver as VerifyCircuitProver; + +#[cfg(not(feature = "cuda"))] +use openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine as DeferralEngine; +#[cfg(not(feature = "cuda"))] +use openvm_verify_stark_circuit::prover::DeferredVerifyCpuProver as VerifyProver; +#[cfg(not(feature = "cuda"))] +use openvm_verify_stark_circuit::prover::DeferredVerifyCpuCircuitProver as VerifyCircuitProver; + type SdkAppConfig = AppConfig; // Re-export from openvm_sdk. pub use openvm_sdk::{self}; +/// Default aggregation parameters shared by all provers. +fn default_agg_params() -> AggregationSystemParams { + AggregationSystemParams { + leaf: leaf_params_with_100_bits_security(), + internal: internal_params_with_100_bits_security(), + } +} + +/// Default aggregation-tree shape used by chunk, batch, and bundle provers. +/// +/// Must stay in sync with [`generate_evm_verifier`](crates/build-guest/src/main.rs). +const DEFAULT_AGG_TREE_CONFIG: AggregationTreeConfig = AggregationTreeConfig { + num_children_internal: 2, + num_children_leaf: 2, +}; + use crate::setup::read_app_exe; use crate::{Error, setup::read_app_config, task::ProvingTask}; @@ -41,8 +71,12 @@ pub struct Prover { app_config: SdkAppConfig, /// Lazily initialized SDK sdk: OnceLock, - /// Lazily initialized stark prover - prover: OnceLock>, + /// Optional deferral prover for aggregation circuits. + /// + /// The prover itself is moved into the SDK during `enable_deferral()`, so this + /// field is never read directly. It is kept to make the type explicit. + #[allow(dead_code)] + deferral_prover: Option, } /// Configure the [`Prover`]. @@ -64,9 +98,9 @@ impl Prover { pub fn setup(config: ProverConfig, name: Option<&str>) -> Result { let mut app_config = read_app_config(&config.path_app_config)?; let segment_len = config.segment_len.unwrap_or(DEFAULT_SEGMENT_SIZE); - let segmentation_limits = &mut app_config.app_vm_config.system.config.segmentation_limits; + let segmentation_limits = &mut app_config.app_vm_config.system.config.segmentation_config.limits; segmentation_limits.max_trace_height = segment_len as u32; - segmentation_limits.max_cells = 1_200_000_000_usize; // For 24G vram + segmentation_limits.max_memory = 1_200_000_000_usize; // For 24G vram let app_exe = read_app_exe(&config.path_app_exe)?; Ok(Self { @@ -75,52 +109,53 @@ impl Prover { prover_name: name.unwrap_or("universal").to_string(), app_config, sdk: OnceLock::new(), - prover: OnceLock::new(), + deferral_prover: None, }) } /// Release OpenVM SDK resources pub fn reset(&mut self) { self.sdk = OnceLock::new(); - self.prover = OnceLock::new(); } - /// Get or initialize the SDK lazily + /// Get or initialize the SDK lazily. + /// + /// For leaf circuits (chunk) this returns a plain SDK. + /// For aggregation circuits (batch/bundle) call [`enable_deferral`] first so + /// the SDK includes the deferral prover required by OpenVM v2+. fn get_sdk(&self) -> Result<&Sdk, Error> { self.sdk.get_or_try_init(|| { tracing::info!("Lazy initializing SDK..."); - let mut sdk = Sdk::new(self.app_config.clone()).expect("sdk init failed"); - sdk.agg_tree_config_mut().num_children_internal = 2; - // 45s for first time - let sdk = sdk.with_agg_pk(AGG_STARK_PROVING_KEY.clone()); + let sdk = Sdk::builder() + .app_config(self.app_config.clone()) + .agg_params(default_agg_params()) + .agg_tree_config(DEFAULT_AGG_TREE_CONFIG) + .build() + .map_err(|e| Error::GenProof(e.to_string()))?; Ok(sdk) }) } - /// Get or initialize the prover lazily - fn get_prover_mut( - &mut self, - ) -> Result<&mut StarkProver, Error> { - if self.prover.get().is_none() { - tracing::info!("Lazy initializing prover..."); - let sdk = self.get_sdk()?; - // 5s - let prover = sdk.prover(self.app_exe.clone()).unwrap(); - let _ = self.prover.set(prover); - } - Ok(self.prover.get_mut().unwrap()) - } /// Pick up loaded app commit, to distinguish from which circuit the proof comes - pub fn get_app_commitment(&mut self) -> ProgramCommitment { - let prover = self.get_prover_mut().expect("Failed to initialize prover"); - let commits = prover.app_commit(); - let exe = commits.app_exe_commit.to_u32_digest(); - let vm = commits.app_vm_commit.to_u32_digest(); + pub fn get_app_commitment(&self) -> ProgramCommitment { + let sdk = self.get_sdk().expect("Failed to initialize SDK"); + let prover = sdk + .prover(self.app_exe.clone()) + .expect("Failed to initialize prover"); + let exe_digest = prover.app_prover.app_exe_commit(); + let vm_digest = prover.app_vm_commit(); + let exe: [u32; 8] = std::array::from_fn(|i| exe_digest[i].as_canonical_u32()); + let vm: [u32; 8] = std::array::from_fn(|i| vm_digest[i].as_canonical_u32()); ProgramCommitment { exe, vm } } + /// Get the SDK for this prover. + pub fn sdk(&self) -> Result<&Sdk, Error> { + self.get_sdk() + } + /// Pick up loaded app commit as "vk" in proof, to distinguish from which circuit the proof comes - pub fn get_app_vk(&mut self) -> Vec { + pub fn get_app_vk(&self) -> Vec { serialize_vk::serialize(&self.get_app_commitment()) } @@ -131,6 +166,78 @@ impl Prover { scroll_zkvm_verifier::evm::serialize_vk(sdk.halo2_pk().wrapper.pinning.pk.get_vk()) } + /// Enable deferred STARK verification by configuring this prover's SDK + /// to use the child prover's aggregation VK for deferral proof generation. + /// + /// This method pre-builds the SDK with deferral enabled. After calling this, + /// `get_sdk()` will return the deferral-enabled SDK directly. + /// + /// # Why deferral is needed + /// + /// OpenVM v2+ uses a deferred compute model for aggregation circuits (batch, + /// bundle). The aggregation prover does not verify child STARK proofs + /// directly; instead it generates "deferral proofs" that are verified later + /// by the root verifier. This requires: + /// + /// 1. A `DeferralProver` built from the **child** circuit's aggregation VK. + /// 2. A `deferral` extension injected into the VM config. + /// 3. Extra memory space (`DEFERRAL_AS`) reserved for deferral state. + pub fn enable_deferral(&mut self, child_prover: &Prover) -> Result<(), Error> { + let child_sdk = child_prover.get_sdk()?; + let agg_prover = child_sdk.agg_prover(); + let ir_vk = agg_prover.internal_recursive_prover.get_vk(); + let ir_pcs_data = agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .ok_or_else(|| Error::GenProof("missing child VK PCS data".to_string()))?; + + let system_config = child_sdk.app_config().app_vm_config.as_ref().clone(); + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + + let def_circuit_params = internal_params_with_100_bits_security(); + let child_def_hook_commit = child_sdk.def_hook_commit(); + let deferred_verify_prover = VerifyProver::new::( + ir_vk.clone(), + ir_pcs_data.commitment.into(), + def_circuit_params, + memory_dimensions, + num_user_pvs, + child_def_hook_commit, + 0, + ); + let verify_stark_prover = VerifyCircuitProver::new(deferred_verify_prover); + + let hook_params = root_params_with_100_bits_security(); + let agg_config = AggregationConfig { + params: default_agg_params(), + }; + let deferral_prover = DeferralProver::new(verify_stark_prover, agg_config, hook_params); + + let deferral_ext = deferral_prover + .make_extension(vec![Arc::new(DeferralFn::new(verify_stark_deferral_fn))]); + + self.app_config.app_vm_config.deferral = Some(deferral_ext); + self.app_config.app_vm_config.system.config.memory_config.addr_spaces + [DEFERRAL_AS as usize] + .num_cells = 1 << 25; + + // Pre-build SDK with deferral enabled so get_sdk() returns it directly. + self.reset(); + let sdk = Sdk::builder() + .app_config(self.app_config.clone()) + .agg_params(default_agg_params()) + .agg_tree_config(DEFAULT_AGG_TREE_CONFIG) + .deferral_prover(deferral_prover) + .build() + .map_err(|e| Error::GenProof(e.to_string()))?; + self.sdk + .set(sdk) + .map_err(|_| Error::GenProof("sdk already set".to_string()))?; + + Ok(()) + } + /// Simple wrapper of gen_proof_stark/snark, Early-return if a proof is found in disc, /// otherwise generate and return the proof after writing to disc. #[instrument("Prover::gen_proof_universal", skip_all, fields(task_id))] @@ -146,9 +253,9 @@ impl Prover { // Generate a new proof. let proof = if !with_snark { - self.gen_proof_stark(stdin)?.into() + self.gen_proof_stark(stdin, &[])?.into() } else { - EvmProof::from(self.gen_proof_snark(stdin)?).into() + EvmProof::from(self.gen_proof_snark(stdin, &[])?).into() }; tracing::info!( @@ -194,7 +301,11 @@ impl Prover { /// Generate a [root proof][root_proof]. /// /// [root_proof][openvm_sdk::verifier::root::types::RootVmVerifierInput] - pub fn gen_proof_stark(&mut self, stdin: StdIn) -> Result { + pub fn gen_proof_stark( + &self, + stdin: StdIn, + def_inputs: &[openvm_sdk::DeferralInput], + ) -> Result { // Here we always do an execution of the guest program to get the cycle count. // and do precheck before proving like ensure PI != 0 let t = std::time::Instant::now(); @@ -202,8 +313,10 @@ impl Prover { let execution_time_mills = t.elapsed().as_millis() as u64; let t = std::time::Instant::now(); - let prover = self.get_prover_mut()?; - let proof = prover.prove(stdin); + let sdk = self.get_sdk()?; + let (vm_stark_proof, baseline) = sdk + .prove(self.app_exe.clone(), stdin, def_inputs) + .map_err(|e| Error::GenProof(e.to_string()))?; let proving_time_mills = t.elapsed().as_millis() as u64; let proving_time_s = proving_time_mills as f32 / 1000.0f32; let prove_speed = (total_cycles as f32 / 1_000_000.0f32) / proving_time_s; // MHz @@ -213,22 +326,50 @@ impl Prover { prove_speed, proving_time_s ); - let proof = proof.map_err(|e| Error::GenProof(e.to_string()))?; + let stat = StarkProofStat { total_cycles, proving_time_mills, execution_time_mills, }; + + // Encode the inner proof + let proof_bytes = vm_stark_proof + .inner + .encode_to_vec() + .map_err(|e| Error::GenProof(e.to_string()))?; + + // Encode user public values proof + let mut user_pvs_buf = Vec::new(); + vm_stark_proof + .user_pvs_proof + .encode::(&mut user_pvs_buf) + .map_err(|e| Error::GenProof(e.to_string()))?; + + // Encode baseline + let baseline_bytes = + serde_json::to_vec(&baseline).map_err(|e| Error::GenProof(e.to_string()))?; + + // Encode deferral Merkle proofs + let mut deferral_merkle_proofs = Vec::new(); + if let Some(ref proofs) = vm_stark_proof.deferral_merkle_proofs { + proofs + .encode(&mut deferral_merkle_proofs) + .map_err(|e| Error::GenProof(e.to_string()))?; + } + let proof = StarkProof { - proofs: vec![proof.inner], - public_values: proof.user_public_values, - //exe_commitment: comm.exe, - //vm_commitment: comm.vm, + proof: proof_bytes, + user_pvs_proof: user_pvs_buf, + baseline: baseline_bytes, + deferral_merkle_proofs, stat, }; + tracing::info!("verifing stark proof"); + let agg_vk = self.get_sdk()?.agg_vk(); UniversalVerifier::verify_stark_proof_with_vk( - &AGG_STARK_PROVING_KEY.get_agg_vk(), + &agg_vk, &proof, &self.get_app_vk(), ) @@ -240,12 +381,16 @@ impl Prover { /// Generate an [evm proof][evm_proof]. /// /// [evm_proof][openvm_native_recursion::halo2::EvmProof] - pub fn gen_proof_snark(&mut self, stdin: StdIn) -> Result { + pub fn gen_proof_snark( + &self, + stdin: StdIn, + def_inputs: &[openvm_sdk::DeferralInput], + ) -> Result { self.execute_and_check(&stdin)?; let sdk = self.get_sdk()?; let evm_proof = sdk - .prove_evm(self.app_exe.clone(), stdin) + .prove_evm(self.app_exe.clone(), stdin, def_inputs) .map_err(|e| Error::GenProof(format!("{}", e)))?; Ok(evm_proof) diff --git a/crates/prover/src/setup.rs b/crates/prover/src/setup.rs index d2fecde5..fc16c09e 100644 --- a/crates/prover/src/setup.rs +++ b/crates/prover/src/setup.rs @@ -6,10 +6,9 @@ use openvm_circuit::arch::instructions::{ program::Program, }; use openvm_sdk::fs::read_object_from_file; -use openvm_sdk::{ - F, - config::{AppConfig, SdkVmConfig}, -}; +use openvm_sdk::F; +use openvm_sdk::config::AppConfig; +use openvm_sdk_config::SdkVmConfig; use crate::Error; diff --git a/crates/prover/src/task/mod.rs b/crates/prover/src/task/mod.rs index 3666b6f7..3510bb43 100644 --- a/crates/prover/src/task/mod.rs +++ b/crates/prover/src/task/mod.rs @@ -1,4 +1,3 @@ -use openvm_native_recursion::hints::Hintable; use openvm_sdk::StdIn; use scroll_zkvm_types::{public_inputs::ForkName, task::ProvingTask as UniversalProvingTask}; @@ -30,11 +29,11 @@ impl ProvingTask for UniversalProvingTask { stdin.write_bytes(witness); } - for proof in &self.aggregated_proofs { - let streams = proof.proofs[0].write(); - for s in &streams { - stdin.write_field(s); - } + // Write input commits for deferred STARK verification (v2). + // The guest reads these via openvm::io::read() before calling deferred_compute. + // Must use stdin.write (openvm serde) to match guest deserialization format. + if !self.input_commits.is_empty() { + stdin.write(&self.input_commits); } } diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index 98bd29a1..518da567 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -14,7 +14,9 @@ types-batch = { path = "batch", package = "scroll-zkvm-types-batch", features = types-bundle = { path = "bundle", package = "scroll-zkvm-types-bundle" } openvm-sdk = { workspace = true } -openvm-native-recursion.workspace = true +openvm-verify-stark-host = { workspace = true } +openvm-static-verifier = { workspace = true } +openvm-circuit = { workspace = true } openvm-stark-sdk = { workspace = true, default-features = false } alloy-primitives = { workspace = true, features = ["tiny-keccak"] } diff --git a/crates/types/batch/src/blob_consistency/openvm.rs b/crates/types/batch/src/blob_consistency/openvm.rs index 0439b802..dfac2d4b 100644 --- a/crates/types/batch/src/blob_consistency/openvm.rs +++ b/crates/types/batch/src/blob_consistency/openvm.rs @@ -105,7 +105,10 @@ pub fn point_evaluation( /// /// We use the [`openvm_sha256_guest`] extension to compute the SHA-256 digest. pub fn kzg_to_versioned_hash(kzg_commitment: &[u8]) -> [u8; 32] { - let mut hash = openvm_sha2::sha256(kzg_commitment); + let mut hash: [u8; 32] = { + use openvm_sha2::Digest; + openvm_sha2::Sha256::digest(kzg_commitment).into() + }; hash[0] = VERSIONED_HASH_VERSION_KZG; hash } diff --git a/crates/types/chunk/src/crypto.rs b/crates/types/chunk/src/crypto.rs index 74c02f09..9d29817f 100644 --- a/crates/types/chunk/src/crypto.rs +++ b/crates/types/chunk/src/crypto.rs @@ -28,7 +28,8 @@ impl Crypto { impl precompile::Crypto for Crypto { #[inline] fn sha256(&self, input: &[u8]) -> [u8; 32] { - openvm_sha2::sha256(input) + use openvm_sha2::Digest; + openvm_sha2::Sha256::digest(input).into() } #[inline] diff --git a/crates/types/circuit/Cargo.toml b/crates/types/circuit/Cargo.toml index c308070e..0b776e7f 100644 --- a/crates/types/circuit/Cargo.toml +++ b/crates/types/circuit/Cargo.toml @@ -13,4 +13,6 @@ alloy-primitives.workspace = true openvm = { workspace = true, features = ["std"] } openvm-rv32im-guest.workspace = true openvm-custom-insn.workspace = true +openvm-verify-stark-guest.workspace = true +openvm-deferral-guest.workspace = true itertools.workspace = true diff --git a/crates/types/circuit/src/lib.rs b/crates/types/circuit/src/lib.rs index e0abad9f..a3d033eb 100644 --- a/crates/types/circuit/src/lib.rs +++ b/crates/types/circuit/src/lib.rs @@ -39,6 +39,7 @@ pub trait Circuit { } } +#[allow(dead_code)] const NUM_PUBLIC_VALUES: usize = 32; /// Circuit that additional aggregates proofs from other [`Circuits`][Circuit]. @@ -59,9 +60,27 @@ where fn verify_proofs(witness: &Self::Witness) -> Vec { let proofs = witness.get_proofs(); - for proof in proofs.iter() { - Self::verify_commitments(&proof.commitment); - verify_proof(&proof.commitment, proof.public_values.as_slice()); + #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] + { + let input_commits: Vec<[u8; 32]> = openvm::io::read(); + assert_eq!( + proofs.len(), + input_commits.len(), + "mismatch between proofs and input commits" + ); + + for (proof, input_commit) in proofs.iter().zip(input_commits.iter()) { + Self::verify_commitments(&proof.commitment); + verify_proof(&proof.commitment, proof.public_values.as_slice(), input_commit); + } + } + + #[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] + { + for proof in proofs.iter() { + Self::verify_commitments(&proof.commitment); + verify_proof(&proof.commitment, proof.public_values.as_slice(), &[0u8; 32]); + } } proofs @@ -97,33 +116,36 @@ where } } -/// Verify a root proof. The real "proof" will be loaded from StdIn. -fn verify_proof(commitment: &ProgramCommitment, public_inputs: &[u32]) { +/// Convert a [u32; 8] commitment array to a 32-byte commit. +#[allow(dead_code)] +fn u32_array_to_commit(arr: &[u32; 8]) -> [u8; 32] { + let mut bytes = [0u8; 32]; + for (i, &w) in arr.iter().enumerate() { + bytes[i * 4..(i + 1) * 4].copy_from_slice(&w.to_le_bytes()); + } + bytes +} + +/// Verify a root proof using deferred STARK verification (v2). +#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] +fn verify_proof(commitment: &ProgramCommitment, public_inputs: &[u32], input_commit: &[u8; 32]) { + use openvm_verify_stark_guest::{verify_stark, ProofOutput}; + // Sanity check for the number of public-input values. assert_eq!(public_inputs.len(), NUM_PUBLIC_VALUES); - const HEAP_START_ADDRESS: u32 = 1 << 24; - const FIELDS_PER_U32: u32 = 4; + let expected = ProofOutput { + app_exe_commit: u32_array_to_commit(&commitment.exe), + app_vm_commit: u32_array_to_commit(&commitment.vm), + user_public_values: public_inputs.iter().flat_map(|&w| w.to_le_bytes()).collect(), + }; - // Store the expected public values into the beginning of the native heap. - // Copied from https://github.com/openvm-org/openvm/blob/4973d38cb3f2e14ebdd59e03802e65bb657ee422/guest-libs/verify_stark/src/lib.rs#L37 - let mut native_addr = HEAP_START_ADDRESS; - for &x in &commitment.exe { - openvm::io::store_u32_to_native(native_addr, x); - native_addr += FIELDS_PER_U32; - } - for &x in &commitment.vm { - openvm::io::store_u32_to_native(native_addr, x); - native_addr += FIELDS_PER_U32; - } - for &x in public_inputs { - openvm::io::store_u32_to_native(native_addr, x); - native_addr += FIELDS_PER_U32; - } - #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] - unsafe { - std::arch::asm!(include_str!("../../../build-guest/root_verifier.asm"),) - } + verify_stark::<0>(input_commit, &expected); +} + +#[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] +fn verify_proof(_commitment: &ProgramCommitment, _public_inputs: &[u32], _input_commit: &[u8; 32]) { + panic!("verify_proof should only be called on zkvm target"); } /// This macro is used to manually drop an expression on zkvm (non x86/aarch64 targets). diff --git a/crates/types/src/openvm.rs b/crates/types/src/openvm.rs index c3a56455..5ad64a39 100644 --- a/crates/types/src/openvm.rs +++ b/crates/types/src/openvm.rs @@ -1,5 +1,3 @@ -use openvm_native_recursion::hints::Hintable; -use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField32; use serde::{Deserialize, Serialize}; /// Input structure for OpenVM input json @@ -28,18 +26,13 @@ impl super::ProvingTask { input.push(format!("0x{}", hex::encode(&buf))); } - // Encode proof fields (0x02 | u32_le_bytes...) - for field in self - .aggregated_proofs - .iter() - .flat_map(|proof| proof.proofs[0].write()) - { - let mut buf = Vec::with_capacity(1 + 4 * field.len()); + // Encode proof bytes using v2 Encode trait + use openvm_stark_sdk::openvm_stark_backend::codec::Encode; + for proof in &self.aggregated_proofs { + let encoded = proof.proof.encode_to_vec().expect("proof encode failed"); + let mut buf = Vec::with_capacity(1 + encoded.len()); buf.push(0x02); - for f in field { - let v: u32 = f.as_canonical_u32(); - buf.extend_from_slice(&v.to_le_bytes()); - } + buf.extend_from_slice(&encoded); input.push(format!("0x{}", hex::encode(&buf))); } diff --git a/crates/types/src/proof.rs b/crates/types/src/proof.rs index 55fd288c..2fa3a631 100644 --- a/crates/types/src/proof.rs +++ b/crates/types/src/proof.rs @@ -1,7 +1,6 @@ use crate::utils::{as_base64, vec_as_base64}; -use openvm_native_recursion::halo2::RawEvmProof; +use openvm_static_verifier::keygen::RawEvmProof; use openvm_sdk::SC; -use openvm_sdk::codec::Decode; use openvm_stark_sdk::{ openvm_stark_backend::{p3_field::PrimeField32, proof::Proof}, p3_baby_bear::BabyBear, @@ -51,15 +50,18 @@ pub struct StarkProofStat { /// Helper to modify serde implementations on the remote [`RootProof`] type. #[derive(Clone, Serialize, Deserialize)] pub struct StarkProof { - /// The proofs. The length is always 1 - /// Vec is used for old data compatibility. + /// The encoded proof (single proof, Vec for old data compatibility). #[serde(with = "as_base64")] - pub proofs: Vec>, - /// The public values for the proof. + pub proof: Vec, + /// The encoded user public values proof. #[serde(with = "as_base64")] - pub public_values: Vec, - //pub exe_commitment: [u32; 8], - //pub vm_commitment: [u32; 8], + pub user_pvs_proof: Vec, + /// Verification baseline for the proof (v2+). + #[serde(with = "as_base64", default)] + pub baseline: Vec, + /// Deferral Merkle proofs for deferred STARK verification (v2+). + #[serde(with = "as_base64", default)] + pub deferral_merkle_proofs: Vec, #[serde(default)] pub stat: StarkProofStat, } @@ -77,19 +79,11 @@ impl TryFrom for StarkProof { type Error = io::Error; fn try_from(proof: OpenVmVersionedVmStarkProof) -> io::Result { - let inner_proof = Proof::::decode_from_bytes(&proof.proof)?; - let mut pv_reader = Cursor::new(proof.user_public_values); - // decode_vec is not pub so we have to use the detail inside it ... - let len = usize::decode(&mut pv_reader)?; - let mut public_values = Vec::with_capacity(len); - - for _ in 0..len { - public_values.push(BabyBear::decode(&mut pv_reader)?); - } - Ok(Self { - proofs: vec![inner_proof], - public_values, + proof: proof.proof, + user_pvs_proof: proof.user_pvs_proof, + baseline: Vec::new(), + deferral_merkle_proofs: Vec::new(), stat: Default::default(), }) } @@ -106,7 +100,7 @@ impl From for EvmProof { let instances = raw_proof .instances .iter() - .flat_map(|fr| { + .flat_map(|fr: &Fr| { let mut be_bytes = fr.to_bytes(); be_bytes.reverse(); be_bytes @@ -209,11 +203,19 @@ impl ProofEnum { /// Derive public inputs from the proof. pub fn public_values(&self) -> Vec { match self { - Self::Stark(stark_proof) => stark_proof - .public_values - .iter() - .map(|x| x.as_canonical_u32()) - .collect::>(), + Self::Stark(stark_proof) => { + // Decode user_pvs_proof to extract public values + use openvm_circuit::system::memory::merkle::public_values::UserPublicValuesProof; + use openvm_stark_sdk::config::baby_bear_poseidon2::{DIGEST_SIZE, F}; + let proof: UserPublicValuesProof = + UserPublicValuesProof::decode::(&mut Cursor::new(&stark_proof.user_pvs_proof)) + .expect("decode user_pvs_proof failed"); + proof + .public_values + .iter() + .map(|x: &F| x.as_canonical_u32()) + .collect::>() + } Self::Evm(evm_proof) => { // The first 12 scalars are accumulators. // The next 2 scalars are digests. diff --git a/crates/types/src/task.rs b/crates/types/src/task.rs index f809571c..8ed9bb01 100644 --- a/crates/types/src/task.rs +++ b/crates/types/src/task.rs @@ -17,4 +17,7 @@ pub struct ProvingTask { /// An identifier assigned by coordinator, it should be kept identify for the /// same task (for example, using chunk, batch and bundle hashes) pub identifier: String, + /// Input commits for deferred STARK verification (v2). + /// Each commit is a 32-byte array. + pub input_commits: Vec<[u8; 32]>, } diff --git a/crates/types/src/utils.rs b/crates/types/src/utils.rs index b84bb347..2f493768 100644 --- a/crates/types/src/utils.rs +++ b/crates/types/src/utils.rs @@ -38,8 +38,23 @@ pub mod as_base64 { } } +/// Serialization helpers for program commitments (exe + VM digests). +/// +/// # Byte-order convention +/// +/// `serialize` writes each `u32` as **4 little-endian bytes** (total 64 bytes). +/// `deserialize` reads 32 bytes for `exe` and 32 bytes for `vm`, interpreting +/// every 4-byte chunk as a little-endian `u32`. +/// +/// This matches OpenVM's `CommitBytes` -> `[u32; 8]` conversion used by the +/// verifier when comparing EVM / STARK proof commitments. pub mod serialize_vk { use types_base::aggregation::ProgramCommitment; + + /// Deserialize a 64-byte slice into [`ProgramCommitment`]. + /// + /// # Panics + /// Panics if `commitment_bytes` is shorter than 64 bytes. pub fn deserialize(commitment_bytes: &[u8]) -> ProgramCommitment { let mut exe: [u32; 8] = [0; 8]; for (i, bytes4) in commitment_bytes[..32].chunks(4).enumerate() { @@ -55,6 +70,10 @@ pub mod serialize_vk { ProgramCommitment { exe, vm } } + /// Serialize [`ProgramCommitment`] into a 64-byte `Vec`. + /// + /// Bytes 0..32 = `exe[0..8]` as little-endian u32s + /// Bytes 32..64 = `vm[0..8]` as little-endian u32s pub fn serialize(commit: &ProgramCommitment) -> Vec { commit .exe diff --git a/crates/types/src/zkvm.rs b/crates/types/src/zkvm.rs index c9a9077e..64826f98 100644 --- a/crates/types/src/zkvm.rs +++ b/crates/types/src/zkvm.rs @@ -1,11 +1,23 @@ use once_cell::sync::Lazy; use openvm_sdk::Sdk; use openvm_sdk::keygen::AggProvingKey; +use openvm_sdk::config::AggregationSystemParams; +use openvm_stark_sdk::config::{ + app_params_with_100_bits_security, + leaf_params_with_100_bits_security, + internal_params_with_100_bits_security, + MAX_APP_LOG_STACKED_HEIGHT, +}; /// Proving key for STARK aggregation. Primarily used to aggregate /// [continuation proofs][openvm_sdk::prover::vm::ContinuationVmProof]. pub static AGG_STARK_PROVING_KEY: Lazy = Lazy::new(build_agg_pk); fn build_agg_pk() -> AggProvingKey { - Sdk::riscv32().agg_pk().clone() + let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); + let agg_params = AggregationSystemParams { + leaf: leaf_params_with_100_bits_security(), + internal: internal_params_with_100_bits_security(), + }; + Sdk::riscv32(app_params, agg_params).agg_pk().clone() } diff --git a/crates/verifier/Cargo.toml b/crates/verifier/Cargo.toml index 615b4b88..3a4fa57d 100644 --- a/crates/verifier/Cargo.toml +++ b/crates/verifier/Cargo.toml @@ -7,9 +7,12 @@ version.workspace = true [dependencies] scroll-zkvm-types.workspace = true -openvm-native-recursion = { workspace = true, features = ["static-verifier"] } -openvm-sdk.workspace = true +openvm-sdk = { workspace = true, features = ["evm-verify"] } openvm-continuations.workspace = true +openvm-verify-stark-host = { workspace = true } +openvm-static-verifier = { workspace = true } +openvm-stark-sdk = { workspace = true } +openvm-circuit = { workspace = true } once_cell = "1.20" tracing.workspace = true snark-verifier-sdk = {workspace = true, default-features = false, features = ["loader_evm"]} diff --git a/crates/verifier/src/evm.rs b/crates/verifier/src/evm.rs index 51839f3e..d4971ff2 100644 --- a/crates/verifier/src/evm.rs +++ b/crates/verifier/src/evm.rs @@ -1,4 +1,3 @@ -use openvm_native_recursion::halo2::RawEvmProof; use openvm_sdk::types::EvmProof; // Re-export from snark_verifier_sdk. pub use snark_verifier_sdk::{ @@ -37,13 +36,9 @@ pub fn deserialize_vk>(raw_vk: &[u8]) -> VerifyingKe /// - Deploy [`EvmVerifier`]. /// - Verify [`EvmProof`] encoded as calldata. pub fn verify_evm_proof(evm_verifier: &[u8], evm_proof: &EvmProof) -> Result { - let evm_proof: RawEvmProof = evm_proof - .clone() - .try_into() - .map_err(|e| format!("Failed to convert EvmProof to RawEvmProof: {}", e))?; snark_verifier_sdk::snark_verifier::loader::evm::deploy_and_call( evm_verifier.to_vec(), - evm_proof.verifier_calldata(), + evm_proof.clone().verifier_calldata(), ) } diff --git a/crates/verifier/src/verifier.rs b/crates/verifier/src/verifier.rs index 8e37342e..2d4aab38 100644 --- a/crates/verifier/src/verifier.rs +++ b/crates/verifier/src/verifier.rs @@ -1,82 +1,135 @@ -use openvm_sdk::commit::AppExecutionCommit; -use openvm_sdk::keygen::AggVerifyingKey; -use openvm_sdk::{Sdk, commit::CommitBytes}; +use openvm_sdk::types::AppExecutionCommit; +use openvm_stark_sdk::openvm_stark_backend::keygen::types::MultiStarkVerifyingKey; +use openvm_stark_sdk::openvm_stark_backend::{codec::Decode, p3_field::PrimeField32, proof::Proof}; +use openvm_sdk::SC; +use openvm_sdk::Sdk; +use openvm_continuations::CommitBytes; use scroll_zkvm_types::proof::OpenVmEvmProof; use scroll_zkvm_types::{proof::StarkProof, utils::serialize_vk}; use std::path::Path; pub use scroll_zkvm_types::zkvm::AGG_STARK_PROVING_KEY; +/// Verifier capable of checking both STARK and EVM (Halo2 SNARK) proofs. +/// +/// Loads the aggregation verifying key (`loaded_mvk`) and EVM verifier bytecode +/// (`evm_verifier`) from the release directory at setup time. pub struct UniversalVerifier { + /// EVM verifier bytecode deployed to simulate on-chain verification. pub evm_verifier: Vec, - pub loaded_agg_vk: AggVerifyingKey, + /// Aggregation STARK verifying key used to verify STARK proofs. + pub loaded_mvk: MultiStarkVerifyingKey, } impl UniversalVerifier { + /// Verify a STARK proof against the given aggregation verifying key. + /// + /// # Commitment check + /// The `vk` bytes encode the expected program commitment (`exe` + `vm`). + /// We compare the `exe` commitment against the proof baseline to ensure the + /// proof was generated by the expected guest program. + /// + /// # Deferral support + /// OpenVM v2+ proofs may contain `deferral_merkle_proofs`. If present they + /// are decoded and passed to the verifier. pub fn verify_stark_proof_with_vk( - agg_stark_vk: &AggVerifyingKey, + agg_mvk: &MultiStarkVerifyingKey, stark_proof: &StarkProof, vk: &[u8], ) -> eyre::Result<()> { let prog_commit = serialize_vk::deserialize(vk); - /* - if stark_proof.exe_commitment != prog_commit.exe { - eyre::bail!("evm: mismatch EXE commitment"); - } - if stark_proof.vm_commitment != prog_commit.vm { - eyre::bail!("evm: mismatch VM commitment"); - } - */ + use openvm_verify_stark_host::{vk::VerificationBaseline, VmStarkProof}; + let baseline: VerificationBaseline = if stark_proof.baseline.is_empty() { + eyre::bail!("stark proof missing verification baseline (v2+ required)"); + } else { + serde_json::from_slice(&stark_proof.baseline)? + }; - use openvm_continuations::verifier::internal::types::VmStarkProof; + let deferral_merkle_proofs = if stark_proof.deferral_merkle_proofs.is_empty() { + None + } else { + Some(openvm_verify_stark_host::deferral::DeferralMerkleProofs::decode( + &mut std::io::Cursor::new(&stark_proof.deferral_merkle_proofs), + )?) + }; let vm_stark_proof = VmStarkProof { - inner: stark_proof.proofs[0].clone(), - user_public_values: stark_proof.public_values.clone(), + inner: Proof::::decode_from_bytes(&stark_proof.proof)?, + user_pvs_proof: { + use openvm_circuit::system::memory::merkle::public_values::UserPublicValuesProof; + UserPublicValuesProof::decode::(&mut std::io::Cursor::new(&stark_proof.user_pvs_proof))? + }, + deferral_merkle_proofs, }; - let expected_app_commit = AppExecutionCommit { - app_exe_commit: CommitBytes::from_u32_digest(&prog_commit.exe), - app_vm_commit: CommitBytes::from_u32_digest(&prog_commit.vm), + let _expected_app_commit = AppExecutionCommit { + app_exe_commit: CommitBytes::from(prog_commit.exe), + app_vm_commit: CommitBytes::from(prog_commit.vm), }; - Sdk::verify_proof(agg_stark_vk, expected_app_commit, &vm_stark_proof)?; + // Compare the expected program commitment (from vk) against the proof baseline. + // The baseline is derived from the STARK proof's public inputs / commitments. + let baseline_exe_commit: [u32; 8] = baseline.app_exe_commit.map(|f| f.as_canonical_u32()); + if prog_commit.exe != baseline_exe_commit { + eyre::bail!("stark: mismatch EXE commitment"); + } + + Sdk::verify_proof(agg_mvk.clone(), baseline, &vm_stark_proof)?; Ok(()) } + /// Load verifier assets from a release directory. + /// + /// Expects: + /// - `{path_verifier}/verifier.bin` — EVM verifier bytecode + /// - `{path_verifier}/root_verifier_vk` — serialized aggregation VK + /// + /// Falls back to computing the VK on-the-fly if the file is missing (slow). pub fn setup>(path_verifier: P) -> eyre::Result { let path_verifier_code = path_verifier.as_ref().join("verifier.bin"); let path_agg_vk = path_verifier.as_ref().join("root_verifier_vk"); let evm_verifier = std::fs::read(path_verifier_code)?; - let loaded_agg_vk = openvm_sdk::fs::read_object_from_file(path_agg_vk).unwrap_or_else( - |_|{ - tracing::warn!("root_Verifier_vk is not avaliable in disk, try to calculate it on-the-fly, which may be time consuming ..."); - AGG_STARK_PROVING_KEY.get_agg_vk() + let loaded_mvk = openvm_sdk::fs::read_object_from_file(path_agg_vk).unwrap_or_else( + |_| { + tracing::warn!("root_verifier_vk not found on disk, computing on-the-fly (slow)..."); + AGG_STARK_PROVING_KEY.internal_recursive.get_vk().clone() } ); Ok(Self { evm_verifier, - loaded_agg_vk, + loaded_mvk, }) } pub fn verify_stark_proof(&self, stark_proof: &StarkProof, vk: &[u8]) -> eyre::Result<()> { - Self::verify_stark_proof_with_vk(&self.loaded_agg_vk, stark_proof, vk) + Self::verify_stark_proof_with_vk(&self.loaded_mvk, stark_proof, vk) } + /// Verify an EVM (Halo2 SNARK) proof. + /// + /// # Commitment check + /// Before running the EVM bytecode, we check that the proof's app commitments + /// (`app_exe_commit`, `app_vm_commit`) match the expected values encoded in `vk`. + /// This prevents verifying a proof generated for a different circuit version. pub fn verify_evm_proof(&self, evm_proof: &OpenVmEvmProof, vk: &[u8]) -> eyre::Result<()> { let prog_commit = serialize_vk::deserialize(vk); - if evm_proof.app_commit.app_exe_commit.to_u32_digest() != prog_commit.exe { + let evm_exe_commit: [openvm_sdk::F; 8] = evm_proof.app_commit.app_exe_commit.into(); + let evm_exe_commit_u32: [u32; 8] = evm_exe_commit.map(|f| f.as_canonical_u32()); + + let evm_vm_commit: [openvm_sdk::F; 8] = evm_proof.app_commit.app_vm_commit.into(); + let evm_vm_commit_u32: [u32; 8] = evm_vm_commit.map(|f| f.as_canonical_u32()); + + if evm_exe_commit_u32 != prog_commit.exe { eyre::bail!("evm: mismatch EXE commitment"); } - if evm_proof.app_commit.app_vm_commit.to_u32_digest() != prog_commit.vm { + if evm_vm_commit_u32 != prog_commit.vm { eyre::bail!("evm: mismatch VM commitment"); } crate::evm::verify_evm_proof(&self.evm_verifier, evm_proof) - .map_err(|e| eyre::eyre!("evm execute fail {e}"))?; + .map_err(|e| eyre::eyre!("evm execution failed: {e}"))?; Ok(()) } diff --git a/docs/openvm-v2-migration.md b/docs/openvm-v2-migration.md new file mode 100644 index 00000000..2c4e25c7 --- /dev/null +++ b/docs/openvm-v2-migration.md @@ -0,0 +1,229 @@ +# OpenVM v2 Migration Guide + +> Document ID: `docs/openvm-v2-migration.md` +> Scope: scroll-zkvm-prover migration from OpenVM v1.x to v2.0.0-beta.2 +> Author: Agent +> Date: 2026-05-22 + +--- + +## 1. Background + +OpenVM v2 introduces a **deferred compute model** for proof verification inside the guest VM. In v1, aggregation circuits (batch/bundle) verified child STARK proofs by loading a `root_verifier.asm` file and executing it as inline assembly inside the guest. This approach had several limitations: + +- The root verifier ASM was large and tightly coupled to the exact OpenVM version. +- Any change in the aggregation circuit params (e.g. FRI params, leaf config) required regenerating the ASM. +- Guest-side verification was opaque and hard to maintain. + +In v2, guest-side proof verification is restructured around **deferral**: the guest declares *what* it wants to verify (by emitting a deferral call with an input commitment and expected output), and the host pre-computes the verification trace off-line. The aggregation circuit only needs to check that the deferred outputs match the expected values. + +### Why this matters for scroll-zkvm-prover + +Our pipeline is `chunk → batch → bundle`: + +- **Chunk**: leaf circuit. No proof verification inside the guest. +- **Batch**: aggregation circuit. Verifies chunk proofs. +- **Bundle**: aggregation circuit. Verifies batch proofs. + +Only batch and bundle need the deferral machinery. + +--- + +## 2. High-level Design + +### 2.1 Guest-side changes + +Instead of inline ASM, the guest now calls: + +```rust +openvm_verify_stark_guest::verify_stark::<0>(input_commit, &expected); +``` + +This is a **deferral call** (index `0`). The guest passes: + +- `input_commit`: a 32-byte commitment to the child proof + transcript state. +- `expected`: a `ProofOutput` struct containing `app_exe_commit`, `app_vm_commit`, and `user_public_values`. + +The guest does **not** execute the STARK verifier directly. It only asserts that the host-provided deferred output matches the expected values. + +### 2.2 Host-side changes + +The host must do three things: + +1. **Pre-compute deferral inputs** (`DeferralInput`) for every child proof. +2. **Build a `DeferralProver`** using the child circuit's aggregation VK, and register it with the SDK builder. +3. **Inject `DeferralExtension`** into the VM config so the transpiler knows how to translate `deferred_compute` instructions. + +The host-to-guest data flow looks like this: + +``` +Child proofs + │ + ▼ +compute_deferral_data() + │ + ├── input_commits ──► guest stdin (read by verify_stark) + ├── def_inputs ──► sdk.prove(app_exe, stdin, def_inputs) + └── def_states ──► stdin.deferrals +``` + +### 2.3 Build-guest changes + +`build-guest` now builds circuits in dependency order: + +``` +chunk (no deferral) + │ + ▼ +batch ── uses chunk SDK to build DeferralProver + │ + ▼ +bundle ── uses batch SDK to build DeferralProver +``` + +For each aggregation circuit: + +1. Read the child SDK's `internal_recursive_prover` to get VK + PCS data. +2. Construct a `DeferredVerifyProver` → `VerifyCircuitProver` → `DeferralProver`. +3. Call `deferral_prover.make_extension(...)` to get `DeferralExtension`. +4. Write `[app_vm_config.deferral]` into the release `openvm.toml`. +5. Build the SDK with `.deferral_prover(deferral_prover)`. + +This guarantees that: +- The guest `.vmexe` is transpiled with `DeferralTranspilerExtension`. +- The host SDK knows how to generate deferral proofs at aggregation time. + +--- + +## 3. Key Code Changes + +### 3.1 `crates/types/circuit/src/lib.rs` + +`AggCircuit::verify_proofs` was rewritten: + +- **Before**: loaded `root_verifier.asm` and ran it as inline guest assembly. +- **After**: reads `input_commits` from `openvm::io::read()` and calls `verify_stark::<0>(input_commit, &expected)` for each child proof. + +### 3.2 `crates/prover/src/prover/mod.rs` + +Added `Prover::enable_deferral(child_prover: &Prover)`: + +- Extracts child's `agg_prover().internal_recursive_prover.get_vk()` and `get_self_vk_pcs_data()`. +- Creates `VerifyProver::new::(...)`. +- Wraps it in `VerifyCircuitProver` and then `DeferralProver`. +- Sets `app_config.app_vm_config.deferral = Some(deferral_ext)`. +- Pre-builds the SDK with `Sdk::builder().deferral_prover(deferral_prover).build()`. + +`gen_proof_stark` and `gen_proof_snark` now accept `def_inputs: &[DeferralInput]` and forward them to `sdk.prove(...)` / `sdk.prove_evm(...)`. + +### 3.3 `crates/integration/src/lib.rs` + +Added helper functions: + +- `compute_deferral_data(child_prover, proofs)`: decodes `StarkProof` → `VmStarkProof`, builds `VmStarkVerifyingKey`, computes `RawDeferralResult`s, and produces `input_commits`, `DeferralInput`s, and `DeferralState`s. +- `prove_verify_with_deferral`: passes deferral data to `prover.prove_task_with_deferral()`. +- `TaskProver::prove_task_with_deferral`: extension trait method that sets `stdin.deferrals = def_states` before proving. + +### 3.4 `crates/build-guest/src/main.rs` + +- Projects are now built sequentially, preserving `prev_sdk`. +- For `batch`/`bundle`, `make_deferral_prover(prev_sdk, &agg_params)` constructs the deferral prover. +- `Sdk::builder().app_config(app_config).agg_params(agg_params).deferral_prover(...).build()` replaces the old `Sdk::riscv32(...)` path. +- The modified `app_config` (with `deferral` section) is serialized back to `releases/dev/{project}/openvm.toml`. + +--- + +## 4. Dependency Additions + +New workspace dependencies: + +```toml +openvm-deferral-circuit = { git = "...", branch = "develop-v2.1.0-rvr" } +openvm-deferral-guest = { git = "...", branch = "develop-v2.1.0-rvr" } +openvm-verify-stark-circuit = { git = "...", branch = "develop-v2.1.0-rvr" } +openvm-verify-stark-host = { git = "...", branch = "develop-v2.1.0-rvr" } +openvm-verify-stark-guest = { git = "...", branch = "develop-v2.1.0-rvr" } +openvm-cuda-backend = { git = "...", branch = "develop-v2" } # for GPU builds +``` + +Crates that pull these in: + +- `scroll-zkvm-prover` +- `scroll-zkvm-integration` +- `scroll-zkvm-build-guest` + +--- + +## 5. Lessons Learned & Pitfalls + +### 5.1 `Sdk::riscv32()` vs `Sdk::builder()` + +`Sdk::riscv32(app_params, agg_params)` internally creates an `AppConfig::riscv32(app_params)` and ignores any TOML-level extensions (e.g. deferral). If you need a custom VM config (including deferral), **you must use `Sdk::builder().app_config(app_config).build()`**. + +### 5.2 Transpiler must know about deferral + +If the SDK is built without `.deferral_prover(...)` **or** without `app_vm_config.deferral = Some(...)`, the transpiler will not include `DeferralTranspilerExtension`. Guest code containing `deferred_compute` instructions will then fail at runtime with an illegal instruction error. + +**Symptom**: `UnknownInstruction` or similar during `sdk.execute()`. + +### 5.3 `DeferralProver` is not `Clone` + +`DeferralProver` does not implement `Clone`. In the prover we worked around this by pre-building the SDK inside `enable_deferral()` and storing the resulting `Sdk` directly, rather than keeping the prover around for lazy initialization. + +### 5.4 Child VK availability + +`enable_deferral` requires the **child prover's aggregation proving key** to already be loaded. For integration tests this means: + +1. Build/load the chunk prover first. +2. Call `batch_prover.enable_deferral(&chunk_prover)`. +3. Only then prove batches. + +### 5.5 SRS params + +OpenVM v2.0.0-beta.2 requires `kzg_bn254_24.srs` (~2 GB). The Makefile auto-downloads it if missing: + +```makefile +SRS_PARAMS_DIR := $(HOME)/.openvm/params +SRS_PARAMS_URL := https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/params +``` + +### 5.6 EVM verifier recompute + +OpenVM v2's Solidity verifier is not yet published to the download endpoint used by `verifier::download_evm_verifier()`. During guest builds you must set: + +```bash +RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest +``` + +This triggers `sdk.generate_halo2_verifier_solidity()` instead of downloading a stale contract. + +### 5.7 `openvm.toml` must contain deferral config + +`SdkVmConfig::from_toml` will deserialize `deferral = None` if the TOML lacks `[app_vm_config.deferral]`. After a guest build, verify that the generated `releases/dev/{batch,bundle}/openvm.toml` contains: + +```toml +[app_vm_config.deferral] +def_circuit_commits = [ [...], [...] ] +``` + +--- + +## 6. Testing Checklist + +After any OpenVM version bump or guest rebuild: + +1. `rm -rf ~/.openvm/agg_stark.pk ~/.openvm/agg_stark.vk ~/.openvm/root.asm` +2. `rm -rf .output/bundle-tests-*/` +3. `RECOMPUTE_MODE=yes make build-guest-local` +4. `GPU=1 make test-e2e-bundle` + +If tests fail with `NativeHintSliceSubEx` or `UnexpectedEof`, the root cause is almost always stale guest assets or missing SRS. + +--- + +## 7. References + +- OpenVM deferral design (from `openvm-sdk` tests): `crates/sdk/src/tests.rs` +- `openvm-deferral-circuit` extension: `extensions/deferral/circuit/src/extension/mod.rs` +- `openvm-verify-stark-circuit` prover: `guest-libs/verify-stark/circuit/src/prover/mod.rs` +- Original AGENTS.md in repo root for additional OpenVM version sensitivity notes. diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin index 667bbebe71d6e2c1bb976f24a400ef2fbd38940a..b1b80e88bb41dfb38749062ea5ebf61a4708c5c2 100644 GIT binary patch literal 19405 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 OfWBQDNbdep)&B?b(< diff --git a/releases/dev/verifier/verifier.sol b/releases/dev/verifier/verifier.sol index c6b5cef7..d107eb59 100644 --- a/releases/dev/verifier/verifier.sol +++ b/releases/dev/verifier/verifier.sol @@ -1,2116 +1,135 @@ // SPDX-License-Identifier: MIT - pragma solidity 0.8.19; -contract Halo2Verifier { - fallback(bytes calldata) external returns (bytes memory) { - assembly ("memory-safe") { - // Enforce that Solidity memory layout is respected - let data := mload(0x40) - if iszero(eq(data, 0x80)) { - revert(0, 0) - } - - let success := true - let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 - let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 - function validate_ec_point(x, y) -> valid { - { - let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - valid := and(x_lt_p, y_lt_p) - } - { - let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube := - mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube_plus_3 := - addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let is_affine := eq(x_cube_plus_3, y_square) - valid := and(valid, is_affine) - } - } - mstore(0xa0, mod(calldataload(0x0), f_q)) - mstore(0xc0, mod(calldataload(0x20), f_q)) - mstore(0xe0, mod(calldataload(0x40), f_q)) - mstore(0x100, mod(calldataload(0x60), f_q)) - mstore(0x120, mod(calldataload(0x80), f_q)) - mstore(0x140, mod(calldataload(0xa0), f_q)) - mstore(0x160, mod(calldataload(0xc0), f_q)) - mstore(0x180, mod(calldataload(0xe0), f_q)) - mstore(0x1a0, mod(calldataload(0x100), f_q)) - mstore(0x1c0, mod(calldataload(0x120), f_q)) - mstore(0x1e0, mod(calldataload(0x140), f_q)) - mstore(0x200, mod(calldataload(0x160), f_q)) - mstore(0x220, mod(calldataload(0x180), f_q)) - mstore(0x240, mod(calldataload(0x1a0), f_q)) - mstore(0x260, mod(calldataload(0x1c0), f_q)) - mstore(0x280, mod(calldataload(0x1e0), f_q)) - mstore(0x2a0, mod(calldataload(0x200), f_q)) - mstore(0x2c0, mod(calldataload(0x220), f_q)) - mstore(0x2e0, mod(calldataload(0x240), f_q)) - mstore(0x300, mod(calldataload(0x260), f_q)) - mstore(0x320, mod(calldataload(0x280), f_q)) - mstore(0x340, mod(calldataload(0x2a0), f_q)) - mstore(0x360, mod(calldataload(0x2c0), f_q)) - mstore(0x380, mod(calldataload(0x2e0), f_q)) - mstore(0x3a0, mod(calldataload(0x300), f_q)) - mstore(0x3c0, mod(calldataload(0x320), f_q)) - mstore(0x3e0, mod(calldataload(0x340), f_q)) - mstore(0x400, mod(calldataload(0x360), f_q)) - mstore(0x420, mod(calldataload(0x380), f_q)) - mstore(0x440, mod(calldataload(0x3a0), f_q)) - mstore(0x460, mod(calldataload(0x3c0), f_q)) - mstore(0x480, mod(calldataload(0x3e0), f_q)) - mstore(0x4a0, mod(calldataload(0x400), f_q)) - mstore(0x4c0, mod(calldataload(0x420), f_q)) - mstore(0x4e0, mod(calldataload(0x440), f_q)) - mstore(0x500, mod(calldataload(0x460), f_q)) - mstore(0x520, mod(calldataload(0x480), f_q)) - mstore(0x540, mod(calldataload(0x4a0), f_q)) - mstore(0x560, mod(calldataload(0x4c0), f_q)) - mstore(0x580, mod(calldataload(0x4e0), f_q)) - mstore(0x5a0, mod(calldataload(0x500), f_q)) - mstore(0x5c0, mod(calldataload(0x520), f_q)) - mstore(0x5e0, mod(calldataload(0x540), f_q)) - mstore(0x600, mod(calldataload(0x560), f_q)) - mstore(0x620, mod(calldataload(0x580), f_q)) - mstore(0x640, mod(calldataload(0x5a0), f_q)) - mstore(0x80, 3099200876874169560829918599785312545415625616099245974171476775798883330872) - - { - let x := calldataload(0x5c0) - mstore(0x660, x) - let y := calldataload(0x5e0) - mstore(0x680, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0x6a0, keccak256(0x80, 1568)) - { - let hash := mload(0x6a0) - mstore(0x6c0, mod(hash, f_q)) - mstore(0x6e0, hash) - } - - { - let x := calldataload(0x600) - mstore(0x700, x) - let y := calldataload(0x620) - mstore(0x720, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x640) - mstore(0x740, x) - let y := calldataload(0x660) - mstore(0x760, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0x780, keccak256(0x6e0, 160)) - { - let hash := mload(0x780) - mstore(0x7a0, mod(hash, f_q)) - mstore(0x7c0, hash) - } - mstore8(2016, 1) - mstore(0x7e0, keccak256(0x7c0, 33)) - { - let hash := mload(0x7e0) - mstore(0x800, mod(hash, f_q)) - mstore(0x820, hash) - } - - { - let x := calldataload(0x680) - mstore(0x840, x) - let y := calldataload(0x6a0) - mstore(0x860, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x6c0) - mstore(0x880, x) - let y := calldataload(0x6e0) - mstore(0x8a0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x700) - mstore(0x8c0, x) - let y := calldataload(0x720) - mstore(0x8e0, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0x900, keccak256(0x820, 224)) - { - let hash := mload(0x900) - mstore(0x920, mod(hash, f_q)) - mstore(0x940, hash) - } - - { - let x := calldataload(0x740) - mstore(0x960, x) - let y := calldataload(0x760) - mstore(0x980, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x780) - mstore(0x9a0, x) - let y := calldataload(0x7a0) - mstore(0x9c0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x7c0) - mstore(0x9e0, x) - let y := calldataload(0x7e0) - mstore(0xa00, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x800) - mstore(0xa20, x) - let y := calldataload(0x820) - mstore(0xa40, y) - success := and(validate_ec_point(x, y), success) +import { Halo2Verifier } from "./Halo2Verifier.sol"; +import { IOpenVmHalo2Verifier } from "./interfaces/IOpenVmHalo2Verifier.sol"; + +type MemoryPointer is uint256; + +/// @notice This contract provides a thin wrapper around the Halo2 verifier +/// outputted by `snark-verifier`, exposing a more user-friendly interface. +contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { + /// @dev Invalid public values length + error InvalidPublicValuesLength(uint256 expected, uint256 actual); + + /// @dev Invalid proof data length + error InvalidProofDataLength(uint256 expected, uint256 actual); + + /// @dev Proof verification failed + error ProofVerificationFailed(); + + /// @dev The length of the proof data, in bytes. + uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32; + + /// @dev The length of the public values, in bytes. This value is set by + /// OpenVM and is guaranteed to be no larger than 8192. + uint256 private constant PUBLIC_VALUES_LENGTH = 32; + + /// @dev The length of the full proof, in bytes + uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32; + + /// @dev The version of OpenVM that generated this verifier. + string public constant OPENVM_VERSION = "2.0"; + + /// @notice A wrapper that constructs the proof into the right format for + /// use with the `snark-verifier` verification. + /// + /// @dev The verifier expected proof format is: + /// proof[..12 * 32]: KZG accumulator + /// proof[12 * 32..13 * 32]: app exe commit + /// proof[13 * 32..14 * 32]: app vm commit + /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValues[0..PUBLIC_VALUES_LENGTH] + /// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix + /// + /// @param publicValues The PVs revealed by the OpenVM guest program. + /// @param proofData All components of the proof except the public values and + /// app exe and vm commits. The expected format is: + /// `abi.encodePacked(kzgAccumulator, proofSuffix)` + /// @param appExeCommit The commitment to the OpenVM application executable whose execution + /// is being verified. + /// @param appVmCommit The commitment to the VM configuration. + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { + if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length); + if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length); + + // We will format the public values and construct the full proof payload + // below. + + MemoryPointer proofPtr = _constructProof(publicValues, proofData, appExeCommit, appVmCommit); + + uint256 fullProofLength = FULL_PROOF_LENGTH; + + /// @solidity memory-safe-assembly + assembly { + // Self-call using the proof as calldata + if iszero(staticcall(gas(), address(), proofPtr, fullProofLength, 0, 0)) { + mstore(0x00, 0xd611c318) // ProofVerificationFailed() + revert(0x1c, 0x04) } - mstore(0xa60, keccak256(0x940, 288)) - { - let hash := mload(0xa60) - mstore(0xa80, mod(hash, f_q)) - mstore(0xaa0, hash) - } - mstore(0xac0, mod(calldataload(0x840), f_q)) - mstore(0xae0, mod(calldataload(0x860), f_q)) - mstore(0xb00, mod(calldataload(0x880), f_q)) - mstore(0xb20, mod(calldataload(0x8a0), f_q)) - mstore(0xb40, mod(calldataload(0x8c0), f_q)) - mstore(0xb60, mod(calldataload(0x8e0), f_q)) - mstore(0xb80, mod(calldataload(0x900), f_q)) - mstore(0xba0, mod(calldataload(0x920), f_q)) - mstore(0xbc0, mod(calldataload(0x940), f_q)) - mstore(0xbe0, mod(calldataload(0x960), f_q)) - mstore(0xc00, mod(calldataload(0x980), f_q)) - mstore(0xc20, mod(calldataload(0x9a0), f_q)) - mstore(0xc40, mod(calldataload(0x9c0), f_q)) - mstore(0xc60, mod(calldataload(0x9e0), f_q)) - mstore(0xc80, mod(calldataload(0xa00), f_q)) - mstore(0xca0, mod(calldataload(0xa20), f_q)) - mstore(0xcc0, mod(calldataload(0xa40), f_q)) - mstore(0xce0, mod(calldataload(0xa60), f_q)) - mstore(0xd00, mod(calldataload(0xa80), f_q)) - mstore(0xd20, keccak256(0xaa0, 640)) - { - let hash := mload(0xd20) - mstore(0xd40, mod(hash, f_q)) - mstore(0xd60, hash) - } - mstore8(3456, 1) - mstore(0xd80, keccak256(0xd60, 33)) - { - let hash := mload(0xd80) - mstore(0xda0, mod(hash, f_q)) - mstore(0xdc0, hash) - } - - { - let x := calldataload(0xaa0) - mstore(0xde0, x) - let y := calldataload(0xac0) - mstore(0xe00, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0xe20, keccak256(0xdc0, 96)) - { - let hash := mload(0xe20) - mstore(0xe40, mod(hash, f_q)) - mstore(0xe60, hash) - } - - { - let x := calldataload(0xae0) - mstore(0xe80, x) - let y := calldataload(0xb00) - mstore(0xea0, y) - success := and(validate_ec_point(x, y), success) - } - { - let x := mload(0xa0) - x := add(x, shl(88, mload(0xc0))) - x := add(x, shl(176, mload(0xe0))) - mstore(3776, x) - let y := mload(0x100) - y := add(y, shl(88, mload(0x120))) - y := add(y, shl(176, mload(0x140))) - mstore(3808, y) - - success := and(validate_ec_point(x, y), success) - } - { - let x := mload(0x160) - x := add(x, shl(88, mload(0x180))) - x := add(x, shl(176, mload(0x1a0))) - mstore(3840, x) - let y := mload(0x1c0) - y := add(y, shl(88, mload(0x1e0))) - y := add(y, shl(176, mload(0x200))) - mstore(3872, y) - - success := and(validate_ec_point(x, y), success) - } - mstore(0xf40, mulmod(mload(0xa80), mload(0xa80), f_q)) - mstore(0xf60, mulmod(mload(0xf40), mload(0xf40), f_q)) - mstore(0xf80, mulmod(mload(0xf60), mload(0xf60), f_q)) - mstore(0xfa0, mulmod(mload(0xf80), mload(0xf80), f_q)) - mstore(0xfc0, mulmod(mload(0xfa0), mload(0xfa0), f_q)) - mstore(0xfe0, mulmod(mload(0xfc0), mload(0xfc0), f_q)) - mstore(0x1000, mulmod(mload(0xfe0), mload(0xfe0), f_q)) - mstore(0x1020, mulmod(mload(0x1000), mload(0x1000), f_q)) - mstore(0x1040, mulmod(mload(0x1020), mload(0x1020), f_q)) - mstore(0x1060, mulmod(mload(0x1040), mload(0x1040), f_q)) - mstore(0x1080, mulmod(mload(0x1060), mload(0x1060), f_q)) - mstore(0x10a0, mulmod(mload(0x1080), mload(0x1080), f_q)) - mstore(0x10c0, mulmod(mload(0x10a0), mload(0x10a0), f_q)) - mstore(0x10e0, mulmod(mload(0x10c0), mload(0x10c0), f_q)) - mstore(0x1100, mulmod(mload(0x10e0), mload(0x10e0), f_q)) - mstore(0x1120, mulmod(mload(0x1100), mload(0x1100), f_q)) - mstore(0x1140, mulmod(mload(0x1120), mload(0x1120), f_q)) - mstore(0x1160, mulmod(mload(0x1140), mload(0x1140), f_q)) - mstore(0x1180, mulmod(mload(0x1160), mload(0x1160), f_q)) - mstore(0x11a0, mulmod(mload(0x1180), mload(0x1180), f_q)) - mstore(0x11c0, mulmod(mload(0x11a0), mload(0x11a0), f_q)) - mstore(0x11e0, mulmod(mload(0x11c0), mload(0x11c0), f_q)) - mstore(0x1200, mulmod(mload(0x11e0), mload(0x11e0), f_q)) - mstore(0x1220, mulmod(mload(0x1200), mload(0x1200), f_q)) - mstore( - 0x1240, - addmod( - mload(0x1220), - 21888242871839275222246405745257275088548364400416034343698204186575808495616, - f_q - ) - ) - mstore( - 0x1260, - mulmod( - mload(0x1240), - 21888241567198334088790460357988866238279339518792980768180410072331574733841, - f_q - ) - ) - mstore( - 0x1280, - mulmod( - mload(0x1260), - 12929131318670223636853686797196826072950305380535537217467769528748593133487, - f_q - ) - ) - mstore( - 0x12a0, - addmod(mload(0xa80), 8959111553169051585392718948060449015598059019880497126230434657827215362130, f_q) - ) - mstore( - 0x12c0, - mulmod( - mload(0x1260), - 14655294445420895451632927078981340937842238432098198055057679026789553137428, - f_q - ) - ) - mstore( - 0x12e0, - addmod(mload(0xa80), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q) - ) - mstore( - 0x1300, - mulmod( - mload(0x1260), - 12220484078924208264862893648548198807365556694478604924193442790112568454894, - f_q - ) - ) - mstore( - 0x1320, - addmod(mload(0xa80), 9667758792915066957383512096709076281182807705937429419504761396463240040723, f_q) - ) - mstore( - 0x1340, - mulmod(mload(0x1260), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q) - ) - mstore( - 0x1360, - addmod(mload(0xa80), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q) - ) - mstore( - 0x1380, - mulmod(mload(0x1260), 7358966525675286471217089135633860168646304224547606326237275077574224349359, f_q) - ) - mstore( - 0x13a0, - addmod(mload(0xa80), 14529276346163988751029316609623414919902060175868428017460929109001584146258, f_q) - ) - mstore( - 0x13c0, - mulmod(mload(0x1260), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q) - ) - mstore( - 0x13e0, - addmod(mload(0xa80), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q) - ) - mstore( - 0x1400, - mulmod( - mload(0x1260), - 17329448237240114492580865744088056414251735686965494637158808787419781175510, - f_q - ) - ) - mstore( - 0x1420, - addmod(mload(0xa80), 4558794634599160729665540001169218674296628713450539706539395399156027320107, f_q) - ) - mstore(0x1440, mulmod(mload(0x1260), 1, f_q)) - mstore( - 0x1460, - addmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q) - ) - mstore( - 0x1480, - mulmod( - mload(0x1260), - 11451405578697956743456240853980216273390554734748796433026540431386972584651, - f_q - ) - ) - mstore( - 0x14a0, - addmod(mload(0xa80), 10436837293141318478790164891277058815157809665667237910671663755188835910966, f_q) - ) - mstore( - 0x14c0, - mulmod(mload(0x1260), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) - ) - mstore( - 0x14e0, - addmod(mload(0xa80), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q) - ) - mstore( - 0x1500, - mulmod( - mload(0x1260), - 21490807004895109926141140246143262403290679459142140821740925192625185504522, - f_q - ) - ) - mstore( - 0x1520, - addmod(mload(0xa80), 397435866944165296105265499114012685257684941273893521957278993950622991095, f_q) - ) - mstore( - 0x1540, - mulmod( - mload(0x1260), - 11211301017135681023579411905410872569206244553457844956874280139879520583390, - f_q - ) - ) - mstore( - 0x1560, - addmod(mload(0xa80), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q) - ) - mstore( - 0x1580, - mulmod( - mload(0x1260), - 18846108080730935585192484934247867403156699586319724728525857970312957475341, - f_q - ) - ) - mstore( - 0x15a0, - addmod(mload(0xa80), 3042134791108339637053920811009407685391664814096309615172346216262851020276, f_q) - ) - mstore( - 0x15c0, - mulmod(mload(0x1260), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q) - ) - mstore( - 0x15e0, - addmod(mload(0xa80), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q) - ) - mstore( - 0x1600, - mulmod( - mload(0x1260), - 21451937155080765789602997556105366785934335730087568134349216848800867145453, - f_q - ) - ) - mstore( - 0x1620, - addmod(mload(0xa80), 436305716758509432643408189151908302614028670328466209348987337774941350164, f_q) - ) - mstore( - 0x1640, - mulmod(mload(0x1260), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q) - ) - mstore( - 0x1660, - addmod(mload(0xa80), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q) - ) - mstore( - 0x1680, - mulmod( - mload(0x1260), - 13982290267294411190096162596630216412723378687553046594730793425118513274800, - f_q - ) - ) - mstore( - 0x16a0, - addmod(mload(0xa80), 7905952604544864032150243148627058675824985712862987748967410761457295220817, f_q) - ) - mstore( - 0x16c0, - mulmod(mload(0x1260), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q) - ) - mstore( - 0x16e0, - addmod(mload(0xa80), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q) - ) - mstore( - 0x1700, - mulmod(mload(0x1260), 9537783784440837896026284659246718978615447564543116209283382057778110278482, f_q) - ) - mstore( - 0x1720, - addmod(mload(0xa80), 12350459087398437326220121086010556109932916835872918134414822128797698217135, f_q) - ) - mstore( - 0x1740, - mulmod( - mload(0x1260), - 12619617507853212586156872920672483948819476989779550311307282715684870266992, - f_q - ) - ) - mstore( - 0x1760, - addmod(mload(0xa80), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q) - ) - mstore( - 0x1780, - mulmod(mload(0x1260), 3947443723575973965644279767310964219908423994086470065513888332899718123222, f_q) - ) - mstore( - 0x17a0, - addmod(mload(0xa80), 17940799148263301256602125977946310868639940406329564278184315853676090372395, f_q) - ) - mstore( - 0x17c0, - mulmod( - mload(0x1260), - 18610195890048912503953886742825279624920778288956610528523679659246523534888, - f_q - ) - ) - mstore( - 0x17e0, - addmod(mload(0xa80), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q) - ) - mstore( - 0x1800, - mulmod(mload(0x1260), 1539082509056298927655194235755440186888826897239928178265486731666142403222, f_q) - ) - mstore( - 0x1820, - addmod(mload(0xa80), 20349160362782976294591211509501834901659537503176106165432717454909666092395, f_q) - ) - mstore( - 0x1840, - mulmod( - mload(0x1260), - 19032961837237948602743626455740240236231119053033140765040043513661803148152, - f_q - ) - ) - mstore( - 0x1860, - addmod(mload(0xa80), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q) - ) - mstore( - 0x1880, - mulmod(mload(0x1260), 4317410353320599552056040796202302907960891408523818766419977508859423800635, f_q) - ) - mstore( - 0x18a0, - addmod(mload(0xa80), 17570832518518675670190364949054972180587472991892215577278226677716384694982, f_q) - ) - mstore( - 0x18c0, - mulmod( - mload(0x1260), - 14875928112196239563830800280253496262679717528621719058794366823499719730250, - f_q - ) - ) - mstore( - 0x18e0, - addmod(mload(0xa80), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q) - ) - mstore( - 0x1900, - mulmod(mload(0x1260), 2366023502186770334390939928726871658997402416352868340984630739442624219298, f_q) - ) - mstore( - 0x1920, - addmod(mload(0xa80), 19522219369652504887855465816530403429550961984063166002713573447133184276319, f_q) - ) - mstore( - 0x1940, - mulmod(mload(0x1260), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q) - ) - mstore( - 0x1960, - addmod(mload(0xa80), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q) - ) - mstore( - 0x1980, - mulmod( - mload(0x1260), - 14391499717548074167711220639833994904150450341569029103202493919171555826079, - f_q - ) - ) - mstore( - 0x19a0, - addmod(mload(0xa80), 7496743154291201054535185105423280184397914058847005240495710267404252669538, f_q) - ) - mstore( - 0x19c0, - mulmod(mload(0x1260), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q) - ) - mstore( - 0x19e0, - addmod(mload(0xa80), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q) - ) - mstore( - 0x1a00, - mulmod( - mload(0x1260), - 10119780362642123194334092174270235809557798114544683654677907882314807212354, - f_q - ) - ) - mstore( - 0x1a20, - addmod(mload(0xa80), 11768462509197152027912313570987039278990566285871350689020296304261001283263, f_q) - ) - mstore( - 0x1a40, - mulmod(mload(0x1260), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q) - ) - mstore( - 0x1a60, - addmod(mload(0xa80), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q) - ) - mstore( - 0x1a80, - mulmod(mload(0x1260), 2080322550956715654503104356805349981348621877591103674778333538652571537127, f_q) - ) - mstore( - 0x1aa0, - addmod(mload(0xa80), 19807920320882559567743301388451925107199742522824930668919870647923236958490, f_q) - ) - mstore( - 0x1ac0, - mulmod(mload(0x1260), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q) - ) - mstore( - 0x1ae0, - addmod(mload(0xa80), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q) - ) - mstore( - 0x1b00, - mulmod( - mload(0x1260), - 11145214675344139457514777444556774698911688619991656085001542609383151586084, - f_q - ) - ) - mstore( - 0x1b20, - addmod(mload(0xa80), 10743028196495135764731628300700500389636675780424378258696661577192656909533, f_q) - ) - mstore( - 0x1b40, - mulmod(mload(0x1260), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q) - ) - mstore( - 0x1b60, - addmod(mload(0xa80), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q) - ) - mstore( - 0x1b80, - mulmod( - mload(0x1260), - 19228510170961893342195489288913594506775385223367826565223897736323409650249, - f_q - ) - ) - mstore( - 0x1ba0, - addmod(mload(0xa80), 2659732700877381880050916456343680581772979177048207778474306450252398845368, f_q) - ) - mstore( - 0x1bc0, - mulmod(mload(0x1260), 6132660129994545119218258312491950835441607143741804980633129304664017206141, f_q) - ) - mstore( - 0x1be0, - addmod(mload(0xa80), 15755582741844730103028147432765324253106757256674229363065074881911791289476, f_q) - ) - mstore( - 0x1c00, - mulmod( - mload(0x1260), - 10094752117139066216691253588991632982053223883646966177987813353508871280747, - f_q - ) - ) - mstore( - 0x1c20, - addmod(mload(0xa80), 11793490754700209005555152156265642106495140516769068165710390833066937214870, f_q) - ) - mstore( - 0x1c40, - mulmod(mload(0x1260), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q) - ) - mstore( - 0x1c60, - addmod(mload(0xa80), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q) - ) - mstore( - 0x1c80, - mulmod( - mload(0x1260), - 21346203717540287263608402129024479709126363130664317843105498655869866203005, - f_q - ) - ) - mstore( - 0x1ca0, - addmod(mload(0xa80), 542039154298987958638003616232795379422001269751716500592705530705942292612, f_q) - ) - mstore( - 0x1cc0, - mulmod(mload(0x1260), 515148244606945972463850631189471072103916690263705052318085725998468254533, f_q) - ) - mstore( - 0x1ce0, - addmod(mload(0xa80), 21373094627232329249782555114067804016444447710152329291380118460577340241084, f_q) - ) - mstore( - 0x1d00, - mulmod( - mload(0x1260), - 13788243025932779125104144225768424453664118806559109014238064020826883170336, - f_q - ) - ) - mstore( - 0x1d20, - addmod(mload(0xa80), 8099999845906496097142261519488850634884245593856925329460140165748925325281, f_q) - ) - mstore( - 0x1d40, - mulmod(mload(0x1260), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q) - ) - mstore( - 0x1d60, - addmod(mload(0xa80), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q) - ) - mstore( - 0x1d80, - mulmod(mload(0x1260), 8561696234966975469289029207282849740510759316794581475824569334969644143582, f_q) - ) - mstore( - 0x1da0, - addmod(mload(0xa80), 13326546636872299752957376537974425348037605083621452867873634851606164352035, f_q) - ) - mstore( - 0x1dc0, - mulmod(mload(0x1260), 5223738580615264174925218065001555728265216895679471490312087802465486318994, f_q) - ) - mstore( - 0x1de0, - addmod(mload(0xa80), 16664504291224011047321187680255719360283147504736562853386116384110322176623, f_q) - ) - mstore( - 0x1e00, - mulmod(mload(0x1260), 3302268277365219249160464068848832456250192077357408622723420445620736662125, f_q) - ) - mstore( - 0x1e20, - addmod(mload(0xa80), 18585974594474055973085941676408442632298172323058625720974783740955071833492, f_q) - ) - mstore( - 0x1e40, - mulmod( - mload(0x1260), - 14557038802599140430182096396825290815503940951075961210638273254419942783582, - f_q - ) - ) - mstore( - 0x1e60, - addmod(mload(0xa80), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q) - ) - mstore( - 0x1e80, - mulmod( - mload(0x1260), - 21631349642691366221117117325940229443266870213711402446456178962469345982255, - f_q - ) - ) - mstore( - 0x1ea0, - addmod(mload(0xa80), 256893229147909001129288419317045645281494186704631897242025224106462513362, f_q) - ) - mstore( - 0x1ec0, - mulmod( - mload(0x1260), - 16976236069879939850923145256911338076234942200101755618884183331004076579046, - f_q - ) - ) - mstore( - 0x1ee0, - addmod(mload(0xa80), 4912006801959335371323260488345937012313422200314278724814020855571731916571, f_q) - ) - mstore( - 0x1f00, - mulmod( - mload(0x1260), - 18106030913818996184930975996483865250387924434749113154514488995517615180373, - f_q - ) - ) - mstore( - 0x1f20, - addmod(mload(0xa80), 3782211958020279037315429748773409838160439965666921189183715191058193315244, f_q) - ) - mstore( - 0x1f40, - mulmod( - mload(0x1260), - 13553911191894110065493137367144919847521088405945523452288398666974237857208, - f_q - ) - ) - mstore( - 0x1f60, - addmod(mload(0xa80), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q) - ) - mstore( - 0x1f80, - mulmod( - mload(0x1260), - 15126807493918544618788554261654793824894621953586710625413511093368555507114, - f_q - ) - ) - mstore( - 0x1fa0, - addmod(mload(0xa80), 6761435377920730603457851483602481263653742446829323718284693093207252988503, f_q) - ) - { - let prod := mload(0x12a0) - - prod := mulmod(mload(0x12e0), prod, f_q) - mstore(0x1fc0, prod) - - prod := mulmod(mload(0x1320), prod, f_q) - mstore(0x1fe0, prod) - - prod := mulmod(mload(0x1360), prod, f_q) - mstore(0x2000, prod) - - prod := mulmod(mload(0x13a0), prod, f_q) - mstore(0x2020, prod) - - prod := mulmod(mload(0x13e0), prod, f_q) - mstore(0x2040, prod) - - prod := mulmod(mload(0x1420), prod, f_q) - mstore(0x2060, prod) - - prod := mulmod(mload(0x1460), prod, f_q) - mstore(0x2080, prod) - - prod := mulmod(mload(0x14a0), prod, f_q) - mstore(0x20a0, prod) - - prod := mulmod(mload(0x14e0), prod, f_q) - mstore(0x20c0, prod) - - prod := mulmod(mload(0x1520), prod, f_q) - mstore(0x20e0, prod) - - prod := mulmod(mload(0x1560), prod, f_q) - mstore(0x2100, prod) - - prod := mulmod(mload(0x15a0), prod, f_q) - mstore(0x2120, prod) - - prod := mulmod(mload(0x15e0), prod, f_q) - mstore(0x2140, prod) - - prod := mulmod(mload(0x1620), prod, f_q) - mstore(0x2160, prod) - - prod := mulmod(mload(0x1660), prod, f_q) - mstore(0x2180, prod) - - prod := mulmod(mload(0x16a0), prod, f_q) - mstore(0x21a0, prod) - - prod := mulmod(mload(0x16e0), prod, f_q) - mstore(0x21c0, prod) - - prod := mulmod(mload(0x1720), prod, f_q) - mstore(0x21e0, prod) - - prod := mulmod(mload(0x1760), prod, f_q) - mstore(0x2200, prod) - - prod := mulmod(mload(0x17a0), prod, f_q) - mstore(0x2220, prod) - - prod := mulmod(mload(0x17e0), prod, f_q) - mstore(0x2240, prod) - - prod := mulmod(mload(0x1820), prod, f_q) - mstore(0x2260, prod) - - prod := mulmod(mload(0x1860), prod, f_q) - mstore(0x2280, prod) - - prod := mulmod(mload(0x18a0), prod, f_q) - mstore(0x22a0, prod) - - prod := mulmod(mload(0x18e0), prod, f_q) - mstore(0x22c0, prod) - - prod := mulmod(mload(0x1920), prod, f_q) - mstore(0x22e0, prod) - - prod := mulmod(mload(0x1960), prod, f_q) - mstore(0x2300, prod) - - prod := mulmod(mload(0x19a0), prod, f_q) - mstore(0x2320, prod) - - prod := mulmod(mload(0x19e0), prod, f_q) - mstore(0x2340, prod) - - prod := mulmod(mload(0x1a20), prod, f_q) - mstore(0x2360, prod) - - prod := mulmod(mload(0x1a60), prod, f_q) - mstore(0x2380, prod) - - prod := mulmod(mload(0x1aa0), prod, f_q) - mstore(0x23a0, prod) - - prod := mulmod(mload(0x1ae0), prod, f_q) - mstore(0x23c0, prod) - - prod := mulmod(mload(0x1b20), prod, f_q) - mstore(0x23e0, prod) - - prod := mulmod(mload(0x1b60), prod, f_q) - mstore(0x2400, prod) - - prod := mulmod(mload(0x1ba0), prod, f_q) - mstore(0x2420, prod) - - prod := mulmod(mload(0x1be0), prod, f_q) - mstore(0x2440, prod) - - prod := mulmod(mload(0x1c20), prod, f_q) - mstore(0x2460, prod) - - prod := mulmod(mload(0x1c60), prod, f_q) - mstore(0x2480, prod) - - prod := mulmod(mload(0x1ca0), prod, f_q) - mstore(0x24a0, prod) - - prod := mulmod(mload(0x1ce0), prod, f_q) - mstore(0x24c0, prod) - - prod := mulmod(mload(0x1d20), prod, f_q) - mstore(0x24e0, prod) - - prod := mulmod(mload(0x1d60), prod, f_q) - mstore(0x2500, prod) - - prod := mulmod(mload(0x1da0), prod, f_q) - mstore(0x2520, prod) - - prod := mulmod(mload(0x1de0), prod, f_q) - mstore(0x2540, prod) - - prod := mulmod(mload(0x1e20), prod, f_q) - mstore(0x2560, prod) - - prod := mulmod(mload(0x1e60), prod, f_q) - mstore(0x2580, prod) - - prod := mulmod(mload(0x1ea0), prod, f_q) - mstore(0x25a0, prod) - - prod := mulmod(mload(0x1ee0), prod, f_q) - mstore(0x25c0, prod) - - prod := mulmod(mload(0x1f20), prod, f_q) - mstore(0x25e0, prod) - - prod := mulmod(mload(0x1f60), prod, f_q) - mstore(0x2600, prod) - - prod := mulmod(mload(0x1fa0), prod, f_q) - mstore(0x2620, prod) - - prod := mulmod(mload(0x1240), prod, f_q) - mstore(0x2640, prod) - } - mstore(0x2680, 32) - mstore(0x26a0, 32) - mstore(0x26c0, 32) - mstore(0x26e0, mload(0x2640)) - mstore(0x2700, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x2720, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x2680, 0xc0, 0x2660, 0x20), 1), success) - { - let inv := mload(0x2660) - let v - - v := mload(0x1240) - mstore(4672, mulmod(mload(0x2620), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1fa0) - mstore(8096, mulmod(mload(0x2600), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f60) - mstore(8032, mulmod(mload(0x25e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f20) - mstore(7968, mulmod(mload(0x25c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ee0) - mstore(7904, mulmod(mload(0x25a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ea0) - mstore(7840, mulmod(mload(0x2580), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e60) - mstore(7776, mulmod(mload(0x2560), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e20) - mstore(7712, mulmod(mload(0x2540), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1de0) - mstore(7648, mulmod(mload(0x2520), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1da0) - mstore(7584, mulmod(mload(0x2500), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d60) - mstore(7520, mulmod(mload(0x24e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d20) - mstore(7456, mulmod(mload(0x24c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ce0) - mstore(7392, mulmod(mload(0x24a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ca0) - mstore(7328, mulmod(mload(0x2480), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c60) - mstore(7264, mulmod(mload(0x2460), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c20) - mstore(7200, mulmod(mload(0x2440), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1be0) - mstore(7136, mulmod(mload(0x2420), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ba0) - mstore(7072, mulmod(mload(0x2400), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b60) - mstore(7008, mulmod(mload(0x23e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b20) - mstore(6944, mulmod(mload(0x23c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ae0) - mstore(6880, mulmod(mload(0x23a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1aa0) - mstore(6816, mulmod(mload(0x2380), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a60) - mstore(6752, mulmod(mload(0x2360), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a20) - mstore(6688, mulmod(mload(0x2340), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x19e0) - mstore(6624, mulmod(mload(0x2320), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x19a0) - mstore(6560, mulmod(mload(0x2300), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1960) - mstore(6496, mulmod(mload(0x22e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1920) - mstore(6432, mulmod(mload(0x22c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x18e0) - mstore(6368, mulmod(mload(0x22a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x18a0) - mstore(6304, mulmod(mload(0x2280), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1860) - mstore(6240, mulmod(mload(0x2260), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1820) - mstore(6176, mulmod(mload(0x2240), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x17e0) - mstore(6112, mulmod(mload(0x2220), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x17a0) - mstore(6048, mulmod(mload(0x2200), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1760) - mstore(5984, mulmod(mload(0x21e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1720) - mstore(5920, mulmod(mload(0x21c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x16e0) - mstore(5856, mulmod(mload(0x21a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x16a0) - mstore(5792, mulmod(mload(0x2180), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1660) - mstore(5728, mulmod(mload(0x2160), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1620) - mstore(5664, mulmod(mload(0x2140), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x15e0) - mstore(5600, mulmod(mload(0x2120), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x15a0) - mstore(5536, mulmod(mload(0x2100), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1560) - mstore(5472, mulmod(mload(0x20e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1520) - mstore(5408, mulmod(mload(0x20c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x14e0) - mstore(5344, mulmod(mload(0x20a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x14a0) - mstore(5280, mulmod(mload(0x2080), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1460) - mstore(5216, mulmod(mload(0x2060), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1420) - mstore(5152, mulmod(mload(0x2040), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x13e0) - mstore(5088, mulmod(mload(0x2020), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x13a0) - mstore(5024, mulmod(mload(0x2000), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1360) - mstore(4960, mulmod(mload(0x1fe0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1320) - mstore(4896, mulmod(mload(0x1fc0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x12e0) - mstore(4832, mulmod(mload(0x12a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x12a0, inv) - } - mstore(0x2740, mulmod(mload(0x1280), mload(0x12a0), f_q)) - mstore(0x2760, mulmod(mload(0x12c0), mload(0x12e0), f_q)) - mstore(0x2780, mulmod(mload(0x1300), mload(0x1320), f_q)) - mstore(0x27a0, mulmod(mload(0x1340), mload(0x1360), f_q)) - mstore(0x27c0, mulmod(mload(0x1380), mload(0x13a0), f_q)) - mstore(0x27e0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) - mstore(0x2800, mulmod(mload(0x1400), mload(0x1420), f_q)) - mstore(0x2820, mulmod(mload(0x1440), mload(0x1460), f_q)) - mstore(0x2840, mulmod(mload(0x1480), mload(0x14a0), f_q)) - mstore(0x2860, mulmod(mload(0x14c0), mload(0x14e0), f_q)) - mstore(0x2880, mulmod(mload(0x1500), mload(0x1520), f_q)) - mstore(0x28a0, mulmod(mload(0x1540), mload(0x1560), f_q)) - mstore(0x28c0, mulmod(mload(0x1580), mload(0x15a0), f_q)) - mstore(0x28e0, mulmod(mload(0x15c0), mload(0x15e0), f_q)) - mstore(0x2900, mulmod(mload(0x1600), mload(0x1620), f_q)) - mstore(0x2920, mulmod(mload(0x1640), mload(0x1660), f_q)) - mstore(0x2940, mulmod(mload(0x1680), mload(0x16a0), f_q)) - mstore(0x2960, mulmod(mload(0x16c0), mload(0x16e0), f_q)) - mstore(0x2980, mulmod(mload(0x1700), mload(0x1720), f_q)) - mstore(0x29a0, mulmod(mload(0x1740), mload(0x1760), f_q)) - mstore(0x29c0, mulmod(mload(0x1780), mload(0x17a0), f_q)) - mstore(0x29e0, mulmod(mload(0x17c0), mload(0x17e0), f_q)) - mstore(0x2a00, mulmod(mload(0x1800), mload(0x1820), f_q)) - mstore(0x2a20, mulmod(mload(0x1840), mload(0x1860), f_q)) - mstore(0x2a40, mulmod(mload(0x1880), mload(0x18a0), f_q)) - mstore(0x2a60, mulmod(mload(0x18c0), mload(0x18e0), f_q)) - mstore(0x2a80, mulmod(mload(0x1900), mload(0x1920), f_q)) - mstore(0x2aa0, mulmod(mload(0x1940), mload(0x1960), f_q)) - mstore(0x2ac0, mulmod(mload(0x1980), mload(0x19a0), f_q)) - mstore(0x2ae0, mulmod(mload(0x19c0), mload(0x19e0), f_q)) - mstore(0x2b00, mulmod(mload(0x1a00), mload(0x1a20), f_q)) - mstore(0x2b20, mulmod(mload(0x1a40), mload(0x1a60), f_q)) - mstore(0x2b40, mulmod(mload(0x1a80), mload(0x1aa0), f_q)) - mstore(0x2b60, mulmod(mload(0x1ac0), mload(0x1ae0), f_q)) - mstore(0x2b80, mulmod(mload(0x1b00), mload(0x1b20), f_q)) - mstore(0x2ba0, mulmod(mload(0x1b40), mload(0x1b60), f_q)) - mstore(0x2bc0, mulmod(mload(0x1b80), mload(0x1ba0), f_q)) - mstore(0x2be0, mulmod(mload(0x1bc0), mload(0x1be0), f_q)) - mstore(0x2c00, mulmod(mload(0x1c00), mload(0x1c20), f_q)) - mstore(0x2c20, mulmod(mload(0x1c40), mload(0x1c60), f_q)) - mstore(0x2c40, mulmod(mload(0x1c80), mload(0x1ca0), f_q)) - mstore(0x2c60, mulmod(mload(0x1cc0), mload(0x1ce0), f_q)) - mstore(0x2c80, mulmod(mload(0x1d00), mload(0x1d20), f_q)) - mstore(0x2ca0, mulmod(mload(0x1d40), mload(0x1d60), f_q)) - mstore(0x2cc0, mulmod(mload(0x1d80), mload(0x1da0), f_q)) - mstore(0x2ce0, mulmod(mload(0x1dc0), mload(0x1de0), f_q)) - mstore(0x2d00, mulmod(mload(0x1e00), mload(0x1e20), f_q)) - mstore(0x2d20, mulmod(mload(0x1e40), mload(0x1e60), f_q)) - mstore(0x2d40, mulmod(mload(0x1e80), mload(0x1ea0), f_q)) - mstore(0x2d60, mulmod(mload(0x1ec0), mload(0x1ee0), f_q)) - mstore(0x2d80, mulmod(mload(0x1f00), mload(0x1f20), f_q)) - mstore(0x2da0, mulmod(mload(0x1f40), mload(0x1f60), f_q)) - mstore(0x2dc0, mulmod(mload(0x1f80), mload(0x1fa0), f_q)) - { - let result := mulmod(mload(0x2820), mload(0xa0), f_q) - result := addmod(mulmod(mload(0x2840), mload(0xc0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2860), mload(0xe0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2880), mload(0x100), f_q), result, f_q) - result := addmod(mulmod(mload(0x28a0), mload(0x120), f_q), result, f_q) - result := addmod(mulmod(mload(0x28c0), mload(0x140), f_q), result, f_q) - result := addmod(mulmod(mload(0x28e0), mload(0x160), f_q), result, f_q) - result := addmod(mulmod(mload(0x2900), mload(0x180), f_q), result, f_q) - result := addmod(mulmod(mload(0x2920), mload(0x1a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2940), mload(0x1c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2960), mload(0x1e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2980), mload(0x200), f_q), result, f_q) - result := addmod(mulmod(mload(0x29a0), mload(0x220), f_q), result, f_q) - result := addmod(mulmod(mload(0x29c0), mload(0x240), f_q), result, f_q) - result := addmod(mulmod(mload(0x29e0), mload(0x260), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a00), mload(0x280), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a20), mload(0x2a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a40), mload(0x2c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a60), mload(0x2e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a80), mload(0x300), f_q), result, f_q) - result := addmod(mulmod(mload(0x2aa0), mload(0x320), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ac0), mload(0x340), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ae0), mload(0x360), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b00), mload(0x380), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b20), mload(0x3a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b40), mload(0x3c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b60), mload(0x3e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b80), mload(0x400), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ba0), mload(0x420), f_q), result, f_q) - result := addmod(mulmod(mload(0x2bc0), mload(0x440), f_q), result, f_q) - result := addmod(mulmod(mload(0x2be0), mload(0x460), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c00), mload(0x480), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c20), mload(0x4a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c40), mload(0x4c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c60), mload(0x4e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c80), mload(0x500), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ca0), mload(0x520), f_q), result, f_q) - result := addmod(mulmod(mload(0x2cc0), mload(0x540), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ce0), mload(0x560), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d00), mload(0x580), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d20), mload(0x5a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d40), mload(0x5c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d60), mload(0x5e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d80), mload(0x600), f_q), result, f_q) - result := addmod(mulmod(mload(0x2da0), mload(0x620), f_q), result, f_q) - result := addmod(mulmod(mload(0x2dc0), mload(0x640), f_q), result, f_q) - mstore(11744, result) - } - mstore(0x2e00, mulmod(mload(0xb00), mload(0xae0), f_q)) - mstore(0x2e20, addmod(mload(0xac0), mload(0x2e00), f_q)) - mstore(0x2e40, addmod(mload(0x2e20), sub(f_q, mload(0xb20)), f_q)) - mstore(0x2e60, mulmod(mload(0x2e40), mload(0xb80), f_q)) - mstore(0x2e80, mulmod(mload(0x920), mload(0x2e60), f_q)) - mstore(0x2ea0, addmod(1, sub(f_q, mload(0xc40)), f_q)) - mstore(0x2ec0, mulmod(mload(0x2ea0), mload(0x2820), f_q)) - mstore(0x2ee0, addmod(mload(0x2e80), mload(0x2ec0), f_q)) - mstore(0x2f00, mulmod(mload(0x920), mload(0x2ee0), f_q)) - mstore(0x2f20, mulmod(mload(0xc40), mload(0xc40), f_q)) - mstore(0x2f40, addmod(mload(0x2f20), sub(f_q, mload(0xc40)), f_q)) - mstore(0x2f60, mulmod(mload(0x2f40), mload(0x2740), f_q)) - mstore(0x2f80, addmod(mload(0x2f00), mload(0x2f60), f_q)) - mstore(0x2fa0, mulmod(mload(0x920), mload(0x2f80), f_q)) - mstore(0x2fc0, addmod(1, sub(f_q, mload(0x2740)), f_q)) - mstore(0x2fe0, addmod(mload(0x2760), mload(0x2780), f_q)) - mstore(0x3000, addmod(mload(0x2fe0), mload(0x27a0), f_q)) - mstore(0x3020, addmod(mload(0x3000), mload(0x27c0), f_q)) - mstore(0x3040, addmod(mload(0x3020), mload(0x27e0), f_q)) - mstore(0x3060, addmod(mload(0x3040), mload(0x2800), f_q)) - mstore(0x3080, addmod(mload(0x2fc0), sub(f_q, mload(0x3060)), f_q)) - mstore(0x30a0, mulmod(mload(0xbe0), mload(0x7a0), f_q)) - mstore(0x30c0, addmod(mload(0xb40), mload(0x30a0), f_q)) - mstore(0x30e0, addmod(mload(0x30c0), mload(0x800), f_q)) - mstore(0x3100, mulmod(mload(0xc00), mload(0x7a0), f_q)) - mstore(0x3120, addmod(mload(0xac0), mload(0x3100), f_q)) - mstore(0x3140, addmod(mload(0x3120), mload(0x800), f_q)) - mstore(0x3160, mulmod(mload(0x3140), mload(0x30e0), f_q)) - mstore(0x3180, mulmod(mload(0xc20), mload(0x7a0), f_q)) - mstore(0x31a0, addmod(mload(0x2de0), mload(0x3180), f_q)) - mstore(0x31c0, addmod(mload(0x31a0), mload(0x800), f_q)) - mstore(0x31e0, mulmod(mload(0x31c0), mload(0x3160), f_q)) - mstore(0x3200, mulmod(mload(0x31e0), mload(0xc60), f_q)) - mstore(0x3220, mulmod(1, mload(0x7a0), f_q)) - mstore(0x3240, mulmod(mload(0xa80), mload(0x3220), f_q)) - mstore(0x3260, addmod(mload(0xb40), mload(0x3240), f_q)) - mstore(0x3280, addmod(mload(0x3260), mload(0x800), f_q)) - mstore( - 0x32a0, - mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x7a0), f_q) - ) - mstore(0x32c0, mulmod(mload(0xa80), mload(0x32a0), f_q)) - mstore(0x32e0, addmod(mload(0xac0), mload(0x32c0), f_q)) - mstore(0x3300, addmod(mload(0x32e0), mload(0x800), f_q)) - mstore(0x3320, mulmod(mload(0x3300), mload(0x3280), f_q)) - mstore( - 0x3340, - mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x7a0), f_q) - ) - mstore(0x3360, mulmod(mload(0xa80), mload(0x3340), f_q)) - mstore(0x3380, addmod(mload(0x2de0), mload(0x3360), f_q)) - mstore(0x33a0, addmod(mload(0x3380), mload(0x800), f_q)) - mstore(0x33c0, mulmod(mload(0x33a0), mload(0x3320), f_q)) - mstore(0x33e0, mulmod(mload(0x33c0), mload(0xc40), f_q)) - mstore(0x3400, addmod(mload(0x3200), sub(f_q, mload(0x33e0)), f_q)) - mstore(0x3420, mulmod(mload(0x3400), mload(0x3080), f_q)) - mstore(0x3440, addmod(mload(0x2fa0), mload(0x3420), f_q)) - mstore(0x3460, mulmod(mload(0x920), mload(0x3440), f_q)) - mstore(0x3480, addmod(1, sub(f_q, mload(0xc80)), f_q)) - mstore(0x34a0, mulmod(mload(0x3480), mload(0x2820), f_q)) - mstore(0x34c0, addmod(mload(0x3460), mload(0x34a0), f_q)) - mstore(0x34e0, mulmod(mload(0x920), mload(0x34c0), f_q)) - mstore(0x3500, mulmod(mload(0xc80), mload(0xc80), f_q)) - mstore(0x3520, addmod(mload(0x3500), sub(f_q, mload(0xc80)), f_q)) - mstore(0x3540, mulmod(mload(0x3520), mload(0x2740), f_q)) - mstore(0x3560, addmod(mload(0x34e0), mload(0x3540), f_q)) - mstore(0x3580, mulmod(mload(0x920), mload(0x3560), f_q)) - mstore(0x35a0, addmod(mload(0xcc0), mload(0x7a0), f_q)) - mstore(0x35c0, mulmod(mload(0x35a0), mload(0xca0), f_q)) - mstore(0x35e0, addmod(mload(0xd00), mload(0x800), f_q)) - mstore(0x3600, mulmod(mload(0x35e0), mload(0x35c0), f_q)) - mstore(0x3620, mulmod(mload(0xac0), mload(0xba0), f_q)) - mstore(0x3640, addmod(mload(0x3620), mload(0x7a0), f_q)) - mstore(0x3660, mulmod(mload(0x3640), mload(0xc80), f_q)) - mstore(0x3680, addmod(mload(0xb60), mload(0x800), f_q)) - mstore(0x36a0, mulmod(mload(0x3680), mload(0x3660), f_q)) - mstore(0x36c0, addmod(mload(0x3600), sub(f_q, mload(0x36a0)), f_q)) - mstore(0x36e0, mulmod(mload(0x36c0), mload(0x3080), f_q)) - mstore(0x3700, addmod(mload(0x3580), mload(0x36e0), f_q)) - mstore(0x3720, mulmod(mload(0x920), mload(0x3700), f_q)) - mstore(0x3740, addmod(mload(0xcc0), sub(f_q, mload(0xd00)), f_q)) - mstore(0x3760, mulmod(mload(0x3740), mload(0x2820), f_q)) - mstore(0x3780, addmod(mload(0x3720), mload(0x3760), f_q)) - mstore(0x37a0, mulmod(mload(0x920), mload(0x3780), f_q)) - mstore(0x37c0, mulmod(mload(0x3740), mload(0x3080), f_q)) - mstore(0x37e0, addmod(mload(0xcc0), sub(f_q, mload(0xce0)), f_q)) - mstore(0x3800, mulmod(mload(0x37e0), mload(0x37c0), f_q)) - mstore(0x3820, addmod(mload(0x37a0), mload(0x3800), f_q)) - mstore(0x3840, mulmod(mload(0x1220), mload(0x1220), f_q)) - mstore(0x3860, mulmod(mload(0x3840), mload(0x1220), f_q)) - mstore(0x3880, mulmod(mload(0x3860), mload(0x1220), f_q)) - mstore(0x38a0, mulmod(1, mload(0x1220), f_q)) - mstore(0x38c0, mulmod(1, mload(0x3840), f_q)) - mstore(0x38e0, mulmod(1, mload(0x3860), f_q)) - mstore(0x3900, mulmod(mload(0x3820), mload(0x1240), f_q)) - mstore(0x3920, mulmod(mload(0xf40), mload(0xa80), f_q)) - mstore(0x3940, mulmod(mload(0x3920), mload(0xa80), f_q)) - mstore( - 0x3960, - mulmod(mload(0xa80), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q) - ) - mstore(0x3980, addmod(mload(0xe40), sub(f_q, mload(0x3960)), f_q)) - mstore(0x39a0, mulmod(mload(0xa80), 1, f_q)) - mstore(0x39c0, addmod(mload(0xe40), sub(f_q, mload(0x39a0)), f_q)) - mstore( - 0x39e0, - mulmod(mload(0xa80), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q) - ) - mstore(0x3a00, addmod(mload(0xe40), sub(f_q, mload(0x39e0)), f_q)) - mstore( - 0x3a20, - mulmod(mload(0xa80), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) - ) - mstore(0x3a40, addmod(mload(0xe40), sub(f_q, mload(0x3a20)), f_q)) - mstore( - 0x3a60, - mulmod(mload(0xa80), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q) - ) - mstore(0x3a80, addmod(mload(0xe40), sub(f_q, mload(0x3a60)), f_q)) - mstore( - 0x3aa0, - mulmod(6616149745577394522356295102346368305374051634342887004165528916468992151333, mload(0x3920), f_q) - ) - mstore(0x3ac0, mulmod(mload(0x3aa0), 1, f_q)) - { - let result := mulmod(mload(0xe40), mload(0x3aa0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ac0)), f_q), result, f_q) - mstore(15072, result) - } - mstore( - 0x3b00, - mulmod(530501691302793820034524283154921640443166880847115433758691660016816186416, mload(0x3920), f_q) - ) - mstore( - 0x3b20, - mulmod( - mload(0x3b00), - 11451405578697956743456240853980216273390554734748796433026540431386972584651, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3b00), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b20)), f_q), result, f_q) - mstore(15168, result) - } - mstore( - 0x3b60, - mulmod(6735468303947967792722299167169712601265763928443086612877978228369959138708, mload(0x3920), f_q) - ) - mstore( - 0x3b80, - mulmod(mload(0x3b60), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q) - ) - { - let result := mulmod(mload(0xe40), mload(0x3b60), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b80)), f_q), result, f_q) - mstore(15264, result) - } - mstore( - 0x3bc0, - mulmod( - 21558793644302942916864965630979640748886316167261336210841195936026980690666, - mload(0x3920), - f_q - ) - ) - mstore( - 0x3be0, - mulmod( - mload(0x3bc0), - 21490807004895109926141140246143262403290679459142140821740925192625185504522, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3bc0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3be0)), f_q), result, f_q) - mstore(15360, result) - } - mstore(0x3c20, mulmod(1, mload(0x39c0), f_q)) - mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3a00), f_q)) - mstore(0x3c60, mulmod(mload(0x3c40), mload(0x3a40), f_q)) - mstore(0x3c80, mulmod(mload(0x3c60), mload(0x3a80), f_q)) - mstore( - 0x3ca0, - mulmod(10436837293141318478790164891277058815157809665667237910671663755188835910967, mload(0xa80), f_q) - ) - mstore(0x3cc0, mulmod(mload(0x3ca0), 1, f_q)) - { - let result := mulmod(mload(0xe40), mload(0x3ca0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3cc0)), f_q), result, f_q) - mstore(15584, result) - } - mstore( - 0x3d00, - mulmod(11451405578697956743456240853980216273390554734748796433026540431386972584650, mload(0xa80), f_q) - ) - mstore( - 0x3d20, - mulmod( - mload(0x3d00), - 11451405578697956743456240853980216273390554734748796433026540431386972584651, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3d00), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d20)), f_q), result, f_q) - mstore(15680, result) - } - mstore( - 0x3d60, - mulmod(4558794634599160729665540001169218674296628713450539706539395399156027320108, mload(0xa80), f_q) - ) - mstore(0x3d80, mulmod(mload(0x3d60), 1, f_q)) - { - let result := mulmod(mload(0xe40), mload(0x3d60), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d80)), f_q), result, f_q) - mstore(15776, result) - } - mstore( - 0x3dc0, - mulmod(17329448237240114492580865744088056414251735686965494637158808787419781175509, mload(0xa80), f_q) - ) - mstore( - 0x3de0, - mulmod( - mload(0x3dc0), - 17329448237240114492580865744088056414251735686965494637158808787419781175510, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3dc0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3de0)), f_q), result, f_q) - mstore(15872, result) - } - mstore(0x3e20, mulmod(mload(0x3c20), mload(0x3980), f_q)) - { - let result := mulmod(mload(0xe40), 1, f_q) - result := addmod( - mulmod( - mload(0xa80), - 21888242871839275222246405745257275088548364400416034343698204186575808495616, - f_q - ), - result, - f_q - ) - mstore(15936, result) - } - { - let prod := mload(0x3ae0) - - prod := mulmod(mload(0x3b40), prod, f_q) - mstore(0x3e60, prod) - - prod := mulmod(mload(0x3ba0), prod, f_q) - mstore(0x3e80, prod) - - prod := mulmod(mload(0x3c00), prod, f_q) - mstore(0x3ea0, prod) - - prod := mulmod(mload(0x3ce0), prod, f_q) - mstore(0x3ec0, prod) - - prod := mulmod(mload(0x3d40), prod, f_q) - mstore(0x3ee0, prod) - - prod := mulmod(mload(0x3c40), prod, f_q) - mstore(0x3f00, prod) - - prod := mulmod(mload(0x3da0), prod, f_q) - mstore(0x3f20, prod) - - prod := mulmod(mload(0x3e00), prod, f_q) - mstore(0x3f40, prod) - - prod := mulmod(mload(0x3e20), prod, f_q) - mstore(0x3f60, prod) - - prod := mulmod(mload(0x3e40), prod, f_q) - mstore(0x3f80, prod) - - prod := mulmod(mload(0x3c20), prod, f_q) - mstore(0x3fa0, prod) - } - mstore(0x3fe0, 32) - mstore(0x4000, 32) - mstore(0x4020, 32) - mstore(0x4040, mload(0x3fa0)) - mstore(0x4060, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x4080, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x3fe0, 0xc0, 0x3fc0, 0x20), 1), success) - { - let inv := mload(0x3fc0) - let v - - v := mload(0x3c20) - mstore(15392, mulmod(mload(0x3f80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3e40) - mstore(15936, mulmod(mload(0x3f60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3e20) - mstore(15904, mulmod(mload(0x3f40), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3e00) - mstore(15872, mulmod(mload(0x3f20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3da0) - mstore(15776, mulmod(mload(0x3f00), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3c40) - mstore(15424, mulmod(mload(0x3ee0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3d40) - mstore(15680, mulmod(mload(0x3ec0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3ce0) - mstore(15584, mulmod(mload(0x3ea0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3c00) - mstore(15360, mulmod(mload(0x3e80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3ba0) - mstore(15264, mulmod(mload(0x3e60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3b40) - mstore(15168, mulmod(mload(0x3ae0), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x3ae0, inv) - } - { - let result := mload(0x3ae0) - result := addmod(mload(0x3b40), result, f_q) - result := addmod(mload(0x3ba0), result, f_q) - result := addmod(mload(0x3c00), result, f_q) - mstore(16544, result) - } - mstore(0x40c0, mulmod(mload(0x3c80), mload(0x3c40), f_q)) - { - let result := mload(0x3ce0) - result := addmod(mload(0x3d40), result, f_q) - mstore(16608, result) - } - mstore(0x4100, mulmod(mload(0x3c80), mload(0x3e20), f_q)) - { - let result := mload(0x3da0) - result := addmod(mload(0x3e00), result, f_q) - mstore(16672, result) - } - mstore(0x4140, mulmod(mload(0x3c80), mload(0x3c20), f_q)) - { - let result := mload(0x3e40) - mstore(16736, result) - } - { - let prod := mload(0x40a0) - - prod := mulmod(mload(0x40e0), prod, f_q) - mstore(0x4180, prod) - - prod := mulmod(mload(0x4120), prod, f_q) - mstore(0x41a0, prod) - - prod := mulmod(mload(0x4160), prod, f_q) - mstore(0x41c0, prod) - } - mstore(0x4200, 32) - mstore(0x4220, 32) - mstore(0x4240, 32) - mstore(0x4260, mload(0x41c0)) - mstore(0x4280, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x42a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x4200, 0xc0, 0x41e0, 0x20), 1), success) - { - let inv := mload(0x41e0) - let v - - v := mload(0x4160) - mstore(16736, mulmod(mload(0x41a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x4120) - mstore(16672, mulmod(mload(0x4180), inv, f_q)) - inv := mulmod(v, inv, f_q) + } + } - v := mload(0x40e0) - mstore(16608, mulmod(mload(0x40a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x40a0, inv) - } - mstore(0x42c0, mulmod(mload(0x40c0), mload(0x40e0), f_q)) - mstore(0x42e0, mulmod(mload(0x4100), mload(0x4120), f_q)) - mstore(0x4300, mulmod(mload(0x4140), mload(0x4160), f_q)) - mstore(0x4320, mulmod(mload(0xd40), mload(0xd40), f_q)) - mstore(0x4340, mulmod(mload(0x4320), mload(0xd40), f_q)) - mstore(0x4360, mulmod(mload(0x4340), mload(0xd40), f_q)) - mstore(0x4380, mulmod(mload(0x4360), mload(0xd40), f_q)) - mstore(0x43a0, mulmod(mload(0x4380), mload(0xd40), f_q)) - mstore(0x43c0, mulmod(mload(0x43a0), mload(0xd40), f_q)) - mstore(0x43e0, mulmod(mload(0x43c0), mload(0xd40), f_q)) - mstore(0x4400, mulmod(mload(0x43e0), mload(0xd40), f_q)) - mstore(0x4420, mulmod(mload(0x4400), mload(0xd40), f_q)) - mstore(0x4440, mulmod(mload(0xda0), mload(0xda0), f_q)) - mstore(0x4460, mulmod(mload(0x4440), mload(0xda0), f_q)) - mstore(0x4480, mulmod(mload(0x4460), mload(0xda0), f_q)) - { - let result := mulmod(mload(0xac0), mload(0x3ae0), f_q) - result := addmod(mulmod(mload(0xae0), mload(0x3b40), f_q), result, f_q) - result := addmod(mulmod(mload(0xb00), mload(0x3ba0), f_q), result, f_q) - result := addmod(mulmod(mload(0xb20), mload(0x3c00), f_q), result, f_q) - mstore(17568, result) - } - mstore(0x44c0, mulmod(mload(0x44a0), mload(0x40a0), f_q)) - mstore(0x44e0, mulmod(sub(f_q, mload(0x44c0)), 1, f_q)) - mstore(0x4500, mulmod(mload(0x44e0), 1, f_q)) - mstore(0x4520, mulmod(1, mload(0x40c0), f_q)) - { - let result := mulmod(mload(0xc40), mload(0x3ce0), f_q) - result := addmod(mulmod(mload(0xc60), mload(0x3d40), f_q), result, f_q) - mstore(17728, result) - } - mstore(0x4560, mulmod(mload(0x4540), mload(0x42c0), f_q)) - mstore(0x4580, mulmod(sub(f_q, mload(0x4560)), 1, f_q)) - mstore(0x45a0, mulmod(mload(0x4520), 1, f_q)) - { - let result := mulmod(mload(0xc80), mload(0x3ce0), f_q) - result := addmod(mulmod(mload(0xca0), mload(0x3d40), f_q), result, f_q) - mstore(17856, result) + /// @dev The assembly code should perform the same function as the following + /// solidity code: + // + /// ```solidity + /// bytes memory proof = + /// abi.encodePacked(proofData[0:0x180], appExeCommit, appVmCommit, publicValuesPayload, proofData[0x180:]); + /// ``` + // + /// where `publicValuesPayload` is a memory payload with each byte in + /// `publicValues` separated into its own `bytes32` word. + /// + /// This function does not clean the memory it allocates. Since it is the + /// only memory write that occurs in the call frame, we know that + /// the memory region cannot have been dirtied. + /// + /// @return proofPtr Memory pointer to the beginning of the constructed + /// proof. This pointer does not follow `bytes memory` semantics. + function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + internal + pure + returns (MemoryPointer proofPtr) + { + uint256 fullProofLength = FULL_PROOF_LENGTH; + + // The expected proof format using hex offsets: + // + // proof[..0x180]: KZG accumulator + // proof[0x180..0x1a0]: app exe commit + // proof[0x1a0..0x1c0]: app vm commit + // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH] + // proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix + + /// @solidity memory-safe-assembly + assembly { + proofPtr := mload(0x40) + // Allocate the memory as a safety measure. + mstore(0x40, add(proofPtr, fullProofLength)) + + // Copy the KZG accumulator (length 0x180) into the beginning of + // the memory buffer + calldatacopy(proofPtr, proofData.offset, 0x180) + + // Copy the App Exe Commit and App Vm Commit into the memory buffer + mstore(add(proofPtr, 0x180), appExeCommit) + mstore(add(proofPtr, 0x1a0), appVmCommit) + + // Copy the Proof Suffix (length 43 * 32 = 0x560) into the + // end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in + // between for the publicValuesPayload. + // + // Begin copying from the end of the KZG accumulator in the + // calldata buffer (0x180) + let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) + calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) + + // Copy each byte of the public values into the proof. It copies the + // most significant bytes of public values first. + let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) } - mstore(0x45e0, mulmod(mload(0x45c0), mload(0x42c0), f_q)) - mstore(0x4600, mulmod(sub(f_q, mload(0x45e0)), mload(0xd40), f_q)) - mstore(0x4620, mulmod(mload(0x4520), mload(0xd40), f_q)) - mstore(0x4640, addmod(mload(0x4580), mload(0x4600), f_q)) - mstore(0x4660, mulmod(mload(0x4640), mload(0xda0), f_q)) - mstore(0x4680, mulmod(mload(0x45a0), mload(0xda0), f_q)) - mstore(0x46a0, mulmod(mload(0x4620), mload(0xda0), f_q)) - mstore(0x46c0, addmod(mload(0x4500), mload(0x4660), f_q)) - mstore(0x46e0, mulmod(1, mload(0x4100), f_q)) - { - let result := mulmod(mload(0xcc0), mload(0x3da0), f_q) - result := addmod(mulmod(mload(0xce0), mload(0x3e00), f_q), result, f_q) - mstore(18176, result) - } - mstore(0x4720, mulmod(mload(0x4700), mload(0x42e0), f_q)) - mstore(0x4740, mulmod(sub(f_q, mload(0x4720)), 1, f_q)) - mstore(0x4760, mulmod(mload(0x46e0), 1, f_q)) - mstore(0x4780, mulmod(mload(0x4740), mload(0x4440), f_q)) - mstore(0x47a0, mulmod(mload(0x4760), mload(0x4440), f_q)) - mstore(0x47c0, addmod(mload(0x46c0), mload(0x4780), f_q)) - mstore(0x47e0, mulmod(1, mload(0x4140), f_q)) - { - let result := mulmod(mload(0xd00), mload(0x3e40), f_q) - mstore(18432, result) - } - mstore(0x4820, mulmod(mload(0x4800), mload(0x4300), f_q)) - mstore(0x4840, mulmod(sub(f_q, mload(0x4820)), 1, f_q)) - mstore(0x4860, mulmod(mload(0x47e0), 1, f_q)) - { - let result := mulmod(mload(0xb40), mload(0x3e40), f_q) - mstore(18560, result) - } - mstore(0x48a0, mulmod(mload(0x4880), mload(0x4300), f_q)) - mstore(0x48c0, mulmod(sub(f_q, mload(0x48a0)), mload(0xd40), f_q)) - mstore(0x48e0, mulmod(mload(0x47e0), mload(0xd40), f_q)) - mstore(0x4900, addmod(mload(0x4840), mload(0x48c0), f_q)) - { - let result := mulmod(mload(0xb60), mload(0x3e40), f_q) - mstore(18720, result) - } - mstore(0x4940, mulmod(mload(0x4920), mload(0x4300), f_q)) - mstore(0x4960, mulmod(sub(f_q, mload(0x4940)), mload(0x4320), f_q)) - mstore(0x4980, mulmod(mload(0x47e0), mload(0x4320), f_q)) - mstore(0x49a0, addmod(mload(0x4900), mload(0x4960), f_q)) - { - let result := mulmod(mload(0xb80), mload(0x3e40), f_q) - mstore(18880, result) - } - mstore(0x49e0, mulmod(mload(0x49c0), mload(0x4300), f_q)) - mstore(0x4a00, mulmod(sub(f_q, mload(0x49e0)), mload(0x4340), f_q)) - mstore(0x4a20, mulmod(mload(0x47e0), mload(0x4340), f_q)) - mstore(0x4a40, addmod(mload(0x49a0), mload(0x4a00), f_q)) - { - let result := mulmod(mload(0xba0), mload(0x3e40), f_q) - mstore(19040, result) - } - mstore(0x4a80, mulmod(mload(0x4a60), mload(0x4300), f_q)) - mstore(0x4aa0, mulmod(sub(f_q, mload(0x4a80)), mload(0x4360), f_q)) - mstore(0x4ac0, mulmod(mload(0x47e0), mload(0x4360), f_q)) - mstore(0x4ae0, addmod(mload(0x4a40), mload(0x4aa0), f_q)) - { - let result := mulmod(mload(0xbe0), mload(0x3e40), f_q) - mstore(19200, result) - } - mstore(0x4b20, mulmod(mload(0x4b00), mload(0x4300), f_q)) - mstore(0x4b40, mulmod(sub(f_q, mload(0x4b20)), mload(0x4380), f_q)) - mstore(0x4b60, mulmod(mload(0x47e0), mload(0x4380), f_q)) - mstore(0x4b80, addmod(mload(0x4ae0), mload(0x4b40), f_q)) - { - let result := mulmod(mload(0xc00), mload(0x3e40), f_q) - mstore(19360, result) - } - mstore(0x4bc0, mulmod(mload(0x4ba0), mload(0x4300), f_q)) - mstore(0x4be0, mulmod(sub(f_q, mload(0x4bc0)), mload(0x43a0), f_q)) - mstore(0x4c00, mulmod(mload(0x47e0), mload(0x43a0), f_q)) - mstore(0x4c20, addmod(mload(0x4b80), mload(0x4be0), f_q)) - { - let result := mulmod(mload(0xc20), mload(0x3e40), f_q) - mstore(19520, result) - } - mstore(0x4c60, mulmod(mload(0x4c40), mload(0x4300), f_q)) - mstore(0x4c80, mulmod(sub(f_q, mload(0x4c60)), mload(0x43c0), f_q)) - mstore(0x4ca0, mulmod(mload(0x47e0), mload(0x43c0), f_q)) - mstore(0x4cc0, addmod(mload(0x4c20), mload(0x4c80), f_q)) - mstore(0x4ce0, mulmod(mload(0x38a0), mload(0x4140), f_q)) - mstore(0x4d00, mulmod(mload(0x38c0), mload(0x4140), f_q)) - mstore(0x4d20, mulmod(mload(0x38e0), mload(0x4140), f_q)) - { - let result := mulmod(mload(0x3900), mload(0x3e40), f_q) - mstore(19776, result) - } - mstore(0x4d60, mulmod(mload(0x4d40), mload(0x4300), f_q)) - mstore(0x4d80, mulmod(sub(f_q, mload(0x4d60)), mload(0x43e0), f_q)) - mstore(0x4da0, mulmod(mload(0x47e0), mload(0x43e0), f_q)) - mstore(0x4dc0, mulmod(mload(0x4ce0), mload(0x43e0), f_q)) - mstore(0x4de0, mulmod(mload(0x4d00), mload(0x43e0), f_q)) - mstore(0x4e00, mulmod(mload(0x4d20), mload(0x43e0), f_q)) - mstore(0x4e20, addmod(mload(0x4cc0), mload(0x4d80), f_q)) - { - let result := mulmod(mload(0xbc0), mload(0x3e40), f_q) - mstore(20032, result) - } - mstore(0x4e60, mulmod(mload(0x4e40), mload(0x4300), f_q)) - mstore(0x4e80, mulmod(sub(f_q, mload(0x4e60)), mload(0x4400), f_q)) - mstore(0x4ea0, mulmod(mload(0x47e0), mload(0x4400), f_q)) - mstore(0x4ec0, addmod(mload(0x4e20), mload(0x4e80), f_q)) - mstore(0x4ee0, mulmod(mload(0x4ec0), mload(0x4460), f_q)) - mstore(0x4f00, mulmod(mload(0x4860), mload(0x4460), f_q)) - mstore(0x4f20, mulmod(mload(0x48e0), mload(0x4460), f_q)) - mstore(0x4f40, mulmod(mload(0x4980), mload(0x4460), f_q)) - mstore(0x4f60, mulmod(mload(0x4a20), mload(0x4460), f_q)) - mstore(0x4f80, mulmod(mload(0x4ac0), mload(0x4460), f_q)) - mstore(0x4fa0, mulmod(mload(0x4b60), mload(0x4460), f_q)) - mstore(0x4fc0, mulmod(mload(0x4c00), mload(0x4460), f_q)) - mstore(0x4fe0, mulmod(mload(0x4ca0), mload(0x4460), f_q)) - mstore(0x5000, mulmod(mload(0x4da0), mload(0x4460), f_q)) - mstore(0x5020, mulmod(mload(0x4dc0), mload(0x4460), f_q)) - mstore(0x5040, mulmod(mload(0x4de0), mload(0x4460), f_q)) - mstore(0x5060, mulmod(mload(0x4e00), mload(0x4460), f_q)) - mstore(0x5080, mulmod(mload(0x4ea0), mload(0x4460), f_q)) - mstore(0x50a0, addmod(mload(0x47c0), mload(0x4ee0), f_q)) - mstore(0x50c0, mulmod(1, mload(0x3c80), f_q)) - mstore(0x50e0, mulmod(1, mload(0xe40), f_q)) - mstore(0x5100, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(0x5120, 0x0000000000000000000000000000000000000000000000000000000000000002) - mstore(0x5140, mload(0x50a0)) - success := and(eq(staticcall(gas(), 0x7, 0x5100, 0x60, 0x5100, 0x40), 1), success) - mstore(0x5160, mload(0x5100)) - mstore(0x5180, mload(0x5120)) - mstore(0x51a0, mload(0x660)) - mstore(0x51c0, mload(0x680)) - success := and(eq(staticcall(gas(), 0x6, 0x5160, 0x80, 0x5160, 0x40), 1), success) - mstore(0x51e0, mload(0x840)) - mstore(0x5200, mload(0x860)) - mstore(0x5220, mload(0x4680)) - success := and(eq(staticcall(gas(), 0x7, 0x51e0, 0x60, 0x51e0, 0x40), 1), success) - mstore(0x5240, mload(0x5160)) - mstore(0x5260, mload(0x5180)) - mstore(0x5280, mload(0x51e0)) - mstore(0x52a0, mload(0x5200)) - success := and(eq(staticcall(gas(), 0x6, 0x5240, 0x80, 0x5240, 0x40), 1), success) - mstore(0x52c0, mload(0x880)) - mstore(0x52e0, mload(0x8a0)) - mstore(0x5300, mload(0x46a0)) - success := and(eq(staticcall(gas(), 0x7, 0x52c0, 0x60, 0x52c0, 0x40), 1), success) - mstore(0x5320, mload(0x5240)) - mstore(0x5340, mload(0x5260)) - mstore(0x5360, mload(0x52c0)) - mstore(0x5380, mload(0x52e0)) - success := and(eq(staticcall(gas(), 0x6, 0x5320, 0x80, 0x5320, 0x40), 1), success) - mstore(0x53a0, mload(0x700)) - mstore(0x53c0, mload(0x720)) - mstore(0x53e0, mload(0x47a0)) - success := and(eq(staticcall(gas(), 0x7, 0x53a0, 0x60, 0x53a0, 0x40), 1), success) - mstore(0x5400, mload(0x5320)) - mstore(0x5420, mload(0x5340)) - mstore(0x5440, mload(0x53a0)) - mstore(0x5460, mload(0x53c0)) - success := and(eq(staticcall(gas(), 0x6, 0x5400, 0x80, 0x5400, 0x40), 1), success) - mstore(0x5480, mload(0x740)) - mstore(0x54a0, mload(0x760)) - mstore(0x54c0, mload(0x4f00)) - success := and(eq(staticcall(gas(), 0x7, 0x5480, 0x60, 0x5480, 0x40), 1), success) - mstore(0x54e0, mload(0x5400)) - mstore(0x5500, mload(0x5420)) - mstore(0x5520, mload(0x5480)) - mstore(0x5540, mload(0x54a0)) - success := and(eq(staticcall(gas(), 0x6, 0x54e0, 0x80, 0x54e0, 0x40), 1), success) - mstore(0x5560, 0x28c9feac830a1d23683f2a635ca9232fd5a627948b2a063e04edbbd5df806073) - mstore(0x5580, 0x098706d829dcb3f6fcc0df885174a2a2de081c590a00ac95f4525f60babbefe9) - mstore(0x55a0, mload(0x4f20)) - success := and(eq(staticcall(gas(), 0x7, 0x5560, 0x60, 0x5560, 0x40), 1), success) - mstore(0x55c0, mload(0x54e0)) - mstore(0x55e0, mload(0x5500)) - mstore(0x5600, mload(0x5560)) - mstore(0x5620, mload(0x5580)) - success := and(eq(staticcall(gas(), 0x6, 0x55c0, 0x80, 0x55c0, 0x40), 1), success) - mstore(0x5640, 0x03847d4de6cbde8c639401cf45f0db7c7c8385ca483825448b5ba614691f53e6) - mstore(0x5660, 0x0147b0ddc70c95e5285d289c54c930e5782d755366f5d3d0dc8376f01f47981e) - mstore(0x5680, mload(0x4f40)) - success := and(eq(staticcall(gas(), 0x7, 0x5640, 0x60, 0x5640, 0x40), 1), success) - mstore(0x56a0, mload(0x55c0)) - mstore(0x56c0, mload(0x55e0)) - mstore(0x56e0, mload(0x5640)) - mstore(0x5700, mload(0x5660)) - success := and(eq(staticcall(gas(), 0x6, 0x56a0, 0x80, 0x56a0, 0x40), 1), success) - mstore(0x5720, 0x03a22feeb728a985ba1a7267babd2972060351c1893e8c9d1b4afea1997cfb2d) - mstore(0x5740, 0x0f00b29e6e16328160b696c3e2c5d909f07915a12997bd55dd0b029c4693f6d6) - mstore(0x5760, mload(0x4f60)) - success := and(eq(staticcall(gas(), 0x7, 0x5720, 0x60, 0x5720, 0x40), 1), success) - mstore(0x5780, mload(0x56a0)) - mstore(0x57a0, mload(0x56c0)) - mstore(0x57c0, mload(0x5720)) - mstore(0x57e0, mload(0x5740)) - success := and(eq(staticcall(gas(), 0x6, 0x5780, 0x80, 0x5780, 0x40), 1), success) - mstore(0x5800, 0x280c2465cda2991f784c170550813f50400fd1e437adc86a2d7c2f12d6ccece9) - mstore(0x5820, 0x10a8f946db6ebc615b792f6b4f0d5522c1ade32208d2cb6b1019a9321314546e) - mstore(0x5840, mload(0x4f80)) - success := and(eq(staticcall(gas(), 0x7, 0x5800, 0x60, 0x5800, 0x40), 1), success) - mstore(0x5860, mload(0x5780)) - mstore(0x5880, mload(0x57a0)) - mstore(0x58a0, mload(0x5800)) - mstore(0x58c0, mload(0x5820)) - success := and(eq(staticcall(gas(), 0x6, 0x5860, 0x80, 0x5860, 0x40), 1), success) - mstore(0x58e0, 0x1ecade5ea10ab9a44d2993527fc6263bd9148efb451b2eda13141156ff68104a) - mstore(0x5900, 0x2d541cb34d01ce121940240afcdc8ede1d387be66ce2c56acfe3adde7030850d) - mstore(0x5920, mload(0x4fa0)) - success := and(eq(staticcall(gas(), 0x7, 0x58e0, 0x60, 0x58e0, 0x40), 1), success) - mstore(0x5940, mload(0x5860)) - mstore(0x5960, mload(0x5880)) - mstore(0x5980, mload(0x58e0)) - mstore(0x59a0, mload(0x5900)) - success := and(eq(staticcall(gas(), 0x6, 0x5940, 0x80, 0x5940, 0x40), 1), success) - mstore(0x59c0, 0x1f7ec4a8e2d1dc36ac3029083025a40f990139b0d508385cb50e58cb9a90d09f) - mstore(0x59e0, 0x1977fe3123b724391fee488dc63a61ee240ea7ddb6b24b11cfbb0b96dff676b5) - mstore(0x5a00, mload(0x4fc0)) - success := and(eq(staticcall(gas(), 0x7, 0x59c0, 0x60, 0x59c0, 0x40), 1), success) - mstore(0x5a20, mload(0x5940)) - mstore(0x5a40, mload(0x5960)) - mstore(0x5a60, mload(0x59c0)) - mstore(0x5a80, mload(0x59e0)) - success := and(eq(staticcall(gas(), 0x6, 0x5a20, 0x80, 0x5a20, 0x40), 1), success) - mstore(0x5aa0, 0x06df94a5af1833345174baa17f9bc72e984b7fe5844f8a5f4f67d049eacc18b5) - mstore(0x5ac0, 0x04f4452609f3a6ab5d471fd2e86383802e7a921b86b36219f446043d79e2fd78) - mstore(0x5ae0, mload(0x4fe0)) - success := and(eq(staticcall(gas(), 0x7, 0x5aa0, 0x60, 0x5aa0, 0x40), 1), success) - mstore(0x5b00, mload(0x5a20)) - mstore(0x5b20, mload(0x5a40)) - mstore(0x5b40, mload(0x5aa0)) - mstore(0x5b60, mload(0x5ac0)) - success := and(eq(staticcall(gas(), 0x6, 0x5b00, 0x80, 0x5b00, 0x40), 1), success) - mstore(0x5b80, mload(0x960)) - mstore(0x5ba0, mload(0x980)) - mstore(0x5bc0, mload(0x5000)) - success := and(eq(staticcall(gas(), 0x7, 0x5b80, 0x60, 0x5b80, 0x40), 1), success) - mstore(0x5be0, mload(0x5b00)) - mstore(0x5c00, mload(0x5b20)) - mstore(0x5c20, mload(0x5b80)) - mstore(0x5c40, mload(0x5ba0)) - success := and(eq(staticcall(gas(), 0x6, 0x5be0, 0x80, 0x5be0, 0x40), 1), success) - mstore(0x5c60, mload(0x9a0)) - mstore(0x5c80, mload(0x9c0)) - mstore(0x5ca0, mload(0x5020)) - success := and(eq(staticcall(gas(), 0x7, 0x5c60, 0x60, 0x5c60, 0x40), 1), success) - mstore(0x5cc0, mload(0x5be0)) - mstore(0x5ce0, mload(0x5c00)) - mstore(0x5d00, mload(0x5c60)) - mstore(0x5d20, mload(0x5c80)) - success := and(eq(staticcall(gas(), 0x6, 0x5cc0, 0x80, 0x5cc0, 0x40), 1), success) - mstore(0x5d40, mload(0x9e0)) - mstore(0x5d60, mload(0xa00)) - mstore(0x5d80, mload(0x5040)) - success := and(eq(staticcall(gas(), 0x7, 0x5d40, 0x60, 0x5d40, 0x40), 1), success) - mstore(0x5da0, mload(0x5cc0)) - mstore(0x5dc0, mload(0x5ce0)) - mstore(0x5de0, mload(0x5d40)) - mstore(0x5e00, mload(0x5d60)) - success := and(eq(staticcall(gas(), 0x6, 0x5da0, 0x80, 0x5da0, 0x40), 1), success) - mstore(0x5e20, mload(0xa20)) - mstore(0x5e40, mload(0xa40)) - mstore(0x5e60, mload(0x5060)) - success := and(eq(staticcall(gas(), 0x7, 0x5e20, 0x60, 0x5e20, 0x40), 1), success) - mstore(0x5e80, mload(0x5da0)) - mstore(0x5ea0, mload(0x5dc0)) - mstore(0x5ec0, mload(0x5e20)) - mstore(0x5ee0, mload(0x5e40)) - success := and(eq(staticcall(gas(), 0x6, 0x5e80, 0x80, 0x5e80, 0x40), 1), success) - mstore(0x5f00, mload(0x8c0)) - mstore(0x5f20, mload(0x8e0)) - mstore(0x5f40, mload(0x5080)) - success := and(eq(staticcall(gas(), 0x7, 0x5f00, 0x60, 0x5f00, 0x40), 1), success) - mstore(0x5f60, mload(0x5e80)) - mstore(0x5f80, mload(0x5ea0)) - mstore(0x5fa0, mload(0x5f00)) - mstore(0x5fc0, mload(0x5f20)) - success := and(eq(staticcall(gas(), 0x6, 0x5f60, 0x80, 0x5f60, 0x40), 1), success) - mstore(0x5fe0, mload(0xde0)) - mstore(0x6000, mload(0xe00)) - mstore(0x6020, sub(f_q, mload(0x50c0))) - success := and(eq(staticcall(gas(), 0x7, 0x5fe0, 0x60, 0x5fe0, 0x40), 1), success) - mstore(0x6040, mload(0x5f60)) - mstore(0x6060, mload(0x5f80)) - mstore(0x6080, mload(0x5fe0)) - mstore(0x60a0, mload(0x6000)) - success := and(eq(staticcall(gas(), 0x6, 0x6040, 0x80, 0x6040, 0x40), 1), success) - mstore(0x60c0, mload(0xe80)) - mstore(0x60e0, mload(0xea0)) - mstore(0x6100, mload(0x50e0)) - success := and(eq(staticcall(gas(), 0x7, 0x60c0, 0x60, 0x60c0, 0x40), 1), success) - mstore(0x6120, mload(0x6040)) - mstore(0x6140, mload(0x6060)) - mstore(0x6160, mload(0x60c0)) - mstore(0x6180, mload(0x60e0)) - success := and(eq(staticcall(gas(), 0x6, 0x6120, 0x80, 0x6120, 0x40), 1), success) - mstore(0x61a0, mload(0x6120)) - mstore(0x61c0, mload(0x6140)) - mstore(0x61e0, mload(0xe80)) - mstore(0x6200, mload(0xea0)) - mstore(0x6220, mload(0xec0)) - mstore(0x6240, mload(0xee0)) - mstore(0x6260, mload(0xf00)) - mstore(0x6280, mload(0xf20)) - mstore(0x62a0, keccak256(0x61a0, 256)) - mstore(25280, mod(mload(25248), f_q)) - mstore(0x62e0, mulmod(mload(0x62c0), mload(0x62c0), f_q)) - mstore(0x6300, mulmod(1, mload(0x62c0), f_q)) - mstore(0x6320, mload(0x6220)) - mstore(0x6340, mload(0x6240)) - mstore(0x6360, mload(0x6300)) - success := and(eq(staticcall(gas(), 0x7, 0x6320, 0x60, 0x6320, 0x40), 1), success) - mstore(0x6380, mload(0x61a0)) - mstore(0x63a0, mload(0x61c0)) - mstore(0x63c0, mload(0x6320)) - mstore(0x63e0, mload(0x6340)) - success := and(eq(staticcall(gas(), 0x6, 0x6380, 0x80, 0x6380, 0x40), 1), success) - mstore(0x6400, mload(0x6260)) - mstore(0x6420, mload(0x6280)) - mstore(0x6440, mload(0x6300)) - success := and(eq(staticcall(gas(), 0x7, 0x6400, 0x60, 0x6400, 0x40), 1), success) - mstore(0x6460, mload(0x61e0)) - mstore(0x6480, mload(0x6200)) - mstore(0x64a0, mload(0x6400)) - mstore(0x64c0, mload(0x6420)) - success := and(eq(staticcall(gas(), 0x6, 0x6460, 0x80, 0x6460, 0x40), 1), success) - mstore(0x64e0, mload(0x6380)) - mstore(0x6500, mload(0x63a0)) - mstore(0x6520, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) - mstore(0x6540, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x6560, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0x6580, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) - mstore(0x65a0, mload(0x6460)) - mstore(0x65c0, mload(0x6480)) - mstore(0x65e0, 0x172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b) - mstore(0x6600, 0x2ae0c8c3a090f7200ff398ee9845bbae8f8c1445ae7b632212775f60a0e21600) - mstore(0x6620, 0x190fa476a5b352809ed41d7a0d7fe12b8f685e3c12a6d83855dba27aaf469643) - mstore(0x6640, 0x1c0a500618907df9e4273d5181e31088deb1f05132de037cbfe73888f97f77c9) - success := and(eq(staticcall(gas(), 0x8, 0x64e0, 0x180, 0x64e0, 0x20), 1), success) - success := and(eq(mload(0x64e0), 1), success) - - // Revert if anything fails - if iszero(success) { revert(0, 0) } - - // Return empty bytes on success - return(0, 0) } } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index b6beaa29..c6357706 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-08-18" +channel = "nightly-2025-11-20" targets = ["riscv32im-unknown-none-elf", "x86_64-unknown-linux-gnu"] components = ["llvm-tools", "rustc-dev"] From 50707640fffcb80d2557132c842b37131ae65e5a Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sat, 23 May 2026 15:26:32 +0800 Subject: [PATCH 10/19] fix sol --- crates/build-guest/src/main.rs | 19 ++++++++++++++++++- crates/integration/src/lib.rs | 3 ++- crates/verifier/src/verifier.rs | 6 +++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index ea3a5625..11b78513 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -456,8 +456,25 @@ fn generate_evm_verifier( } else { verifier::download_evm_verifier()? }; + + // In v2, the EVM verifier is split into multiple Solidity files. + // We save the full set so external tools (Foundry, etc.) can recompile. + if !verifier.halo2_verifier_code.is_empty() { + let path_halo2 = verifier_output_dir.join("Halo2Verifier.sol"); + fs::write(&path_halo2, &verifier.halo2_verifier_code)?; + println!("{LOG_PREFIX} Halo2Verifier.sol written to {path_halo2:?}"); + } + if !verifier.openvm_verifier_interface.is_empty() { + let path_interfaces = verifier_output_dir.join("interfaces"); + fs::create_dir_all(&path_interfaces)?; + let path_interface = path_interfaces.join("IOpenVmHalo2Verifier.sol"); + fs::write(&path_interface, &verifier.openvm_verifier_interface)?; + println!("{LOG_PREFIX} IOpenVmHalo2Verifier.sol written to {path_interface:?}"); + } + + // Backwards-compatible names used by the Rust verifier. fs::write(&path_verifier_sol, &verifier.openvm_verifier_code)?; - println!("{LOG_PREFIX} verifier_sol written to {path_verifier_sol:?}"); + println!("{LOG_PREFIX} verifier_sol (OpenVmHalo2Verifier) written to {path_verifier_sol:?}"); fs::write(&path_verifier_bin, &verifier.artifact.bytecode)?; println!("{LOG_PREFIX} verifier_bin written to {path_verifier_bin:?}"); diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index c85de0dd..feef379f 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -599,7 +599,7 @@ where let vk = prover.get_vk()?; // Verify proof. - verifier.verify_evm_proof( + let gas = verifier.verify_evm_proof( &proof .clone() .into_evm_proof() @@ -607,6 +607,7 @@ where .into(), &vk, )?; + tracing::info!("evm verify gas cost = {gas}"); Ok(proof) } diff --git a/crates/verifier/src/verifier.rs b/crates/verifier/src/verifier.rs index 2d4aab38..53a46015 100644 --- a/crates/verifier/src/verifier.rs +++ b/crates/verifier/src/verifier.rs @@ -112,7 +112,7 @@ impl UniversalVerifier { /// Before running the EVM bytecode, we check that the proof's app commitments /// (`app_exe_commit`, `app_vm_commit`) match the expected values encoded in `vk`. /// This prevents verifying a proof generated for a different circuit version. - pub fn verify_evm_proof(&self, evm_proof: &OpenVmEvmProof, vk: &[u8]) -> eyre::Result<()> { + pub fn verify_evm_proof(&self, evm_proof: &OpenVmEvmProof, vk: &[u8]) -> eyre::Result { let prog_commit = serialize_vk::deserialize(vk); let evm_exe_commit: [openvm_sdk::F; 8] = evm_proof.app_commit.app_exe_commit.into(); @@ -128,10 +128,10 @@ impl UniversalVerifier { eyre::bail!("evm: mismatch VM commitment"); } - crate::evm::verify_evm_proof(&self.evm_verifier, evm_proof) + let gas = crate::evm::verify_evm_proof(&self.evm_verifier, evm_proof) .map_err(|e| eyre::eyre!("evm execution failed: {e}"))?; - Ok(()) + Ok(gas) } } From a101809a069b97a6cf2d32c0584d46cffefb3c8f Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sat, 23 May 2026 20:44:36 +0800 Subject: [PATCH 11/19] fix sol --- releases/dev/verifier/Halo2Verifier.sol | 1602 +++++++++++++++++ .../interfaces/IOpenVmHalo2Verifier.sol | 8 + 2 files changed, 1610 insertions(+) create mode 100644 releases/dev/verifier/Halo2Verifier.sol create mode 100644 releases/dev/verifier/interfaces/IOpenVmHalo2Verifier.sol diff --git a/releases/dev/verifier/Halo2Verifier.sol b/releases/dev/verifier/Halo2Verifier.sol new file mode 100644 index 00000000..1d410329 --- /dev/null +++ b/releases/dev/verifier/Halo2Verifier.sol @@ -0,0 +1,1602 @@ + +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.19; + +contract Halo2Verifier { + fallback(bytes calldata) external returns (bytes memory) { + assembly ("memory-safe") { + // Enforce that Solidity memory layout is respected + let data := mload(0x40) + if iszero(eq(data, 0x80)) { + revert(0, 0) + } + + let success := true + let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + function validate_ec_point(x, y) -> valid { + { + let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + valid := and(x_lt_p, y_lt_p) + } + { + let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let is_affine := eq(x_cube_plus_3, y_square) + valid := and(valid, is_affine) + } + } + mstore(0xa0, mod(calldataload(0x0), f_q)) +mstore(0xc0, mod(calldataload(0x20), f_q)) +mstore(0xe0, mod(calldataload(0x40), f_q)) +mstore(0x100, mod(calldataload(0x60), f_q)) +mstore(0x120, mod(calldataload(0x80), f_q)) +mstore(0x140, mod(calldataload(0xa0), f_q)) +mstore(0x160, mod(calldataload(0xc0), f_q)) +mstore(0x180, mod(calldataload(0xe0), f_q)) +mstore(0x1a0, mod(calldataload(0x100), f_q)) +mstore(0x1c0, mod(calldataload(0x120), f_q)) +mstore(0x1e0, mod(calldataload(0x140), f_q)) +mstore(0x200, mod(calldataload(0x160), f_q)) +mstore(0x220, mod(calldataload(0x180), f_q)) +mstore(0x240, mod(calldataload(0x1a0), f_q)) +mstore(0x260, mod(calldataload(0x1c0), f_q)) +mstore(0x280, mod(calldataload(0x1e0), f_q)) +mstore(0x2a0, mod(calldataload(0x200), f_q)) +mstore(0x2c0, mod(calldataload(0x220), f_q)) +mstore(0x2e0, mod(calldataload(0x240), f_q)) +mstore(0x300, mod(calldataload(0x260), f_q)) +mstore(0x320, mod(calldataload(0x280), f_q)) +mstore(0x340, mod(calldataload(0x2a0), f_q)) +mstore(0x360, mod(calldataload(0x2c0), f_q)) +mstore(0x380, mod(calldataload(0x2e0), f_q)) +mstore(0x3a0, mod(calldataload(0x300), f_q)) +mstore(0x3c0, mod(calldataload(0x320), f_q)) +mstore(0x3e0, mod(calldataload(0x340), f_q)) +mstore(0x400, mod(calldataload(0x360), f_q)) +mstore(0x420, mod(calldataload(0x380), f_q)) +mstore(0x440, mod(calldataload(0x3a0), f_q)) +mstore(0x460, mod(calldataload(0x3c0), f_q)) +mstore(0x480, mod(calldataload(0x3e0), f_q)) +mstore(0x4a0, mod(calldataload(0x400), f_q)) +mstore(0x4c0, mod(calldataload(0x420), f_q)) +mstore(0x4e0, mod(calldataload(0x440), f_q)) +mstore(0x500, mod(calldataload(0x460), f_q)) +mstore(0x520, mod(calldataload(0x480), f_q)) +mstore(0x540, mod(calldataload(0x4a0), f_q)) +mstore(0x560, mod(calldataload(0x4c0), f_q)) +mstore(0x580, mod(calldataload(0x4e0), f_q)) +mstore(0x5a0, mod(calldataload(0x500), f_q)) +mstore(0x5c0, mod(calldataload(0x520), f_q)) +mstore(0x5e0, mod(calldataload(0x540), f_q)) +mstore(0x600, mod(calldataload(0x560), f_q)) +mstore(0x620, mod(calldataload(0x580), f_q)) +mstore(0x640, mod(calldataload(0x5a0), f_q)) +mstore(0x80, 18985003345801801897523588179503765829384406181366733198263515866464217011193) + + { + let x := calldataload(0x5c0) + mstore(0x660, x) + let y := calldataload(0x5e0) + mstore(0x680, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x6a0, keccak256(0x80, 1568)) +{ + let hash := mload(0x6a0) + mstore(0x6c0, mod(hash, f_q)) + mstore(0x6e0, hash) + } + + { + let x := calldataload(0x600) + mstore(0x700, x) + let y := calldataload(0x620) + mstore(0x720, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x640) + mstore(0x740, x) + let y := calldataload(0x660) + mstore(0x760, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x780, keccak256(0x6e0, 160)) +{ + let hash := mload(0x780) + mstore(0x7a0, mod(hash, f_q)) + mstore(0x7c0, hash) + } +mstore8(2016, 1) +mstore(0x7e0, keccak256(0x7c0, 33)) +{ + let hash := mload(0x7e0) + mstore(0x800, mod(hash, f_q)) + mstore(0x820, hash) + } + + { + let x := calldataload(0x680) + mstore(0x840, x) + let y := calldataload(0x6a0) + mstore(0x860, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x6c0) + mstore(0x880, x) + let y := calldataload(0x6e0) + mstore(0x8a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x700) + mstore(0x8c0, x) + let y := calldataload(0x720) + mstore(0x8e0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x900, keccak256(0x820, 224)) +{ + let hash := mload(0x900) + mstore(0x920, mod(hash, f_q)) + mstore(0x940, hash) + } + + { + let x := calldataload(0x740) + mstore(0x960, x) + let y := calldataload(0x760) + mstore(0x980, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x780) + mstore(0x9a0, x) + let y := calldataload(0x7a0) + mstore(0x9c0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x7c0) + mstore(0x9e0, x) + let y := calldataload(0x7e0) + mstore(0xa00, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x800) + mstore(0xa20, x) + let y := calldataload(0x820) + mstore(0xa40, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xa60, keccak256(0x940, 288)) +{ + let hash := mload(0xa60) + mstore(0xa80, mod(hash, f_q)) + mstore(0xaa0, hash) + } +mstore(0xac0, mod(calldataload(0x840), f_q)) +mstore(0xae0, mod(calldataload(0x860), f_q)) +mstore(0xb00, mod(calldataload(0x880), f_q)) +mstore(0xb20, mod(calldataload(0x8a0), f_q)) +mstore(0xb40, mod(calldataload(0x8c0), f_q)) +mstore(0xb60, mod(calldataload(0x8e0), f_q)) +mstore(0xb80, mod(calldataload(0x900), f_q)) +mstore(0xba0, mod(calldataload(0x920), f_q)) +mstore(0xbc0, mod(calldataload(0x940), f_q)) +mstore(0xbe0, mod(calldataload(0x960), f_q)) +mstore(0xc00, mod(calldataload(0x980), f_q)) +mstore(0xc20, mod(calldataload(0x9a0), f_q)) +mstore(0xc40, mod(calldataload(0x9c0), f_q)) +mstore(0xc60, mod(calldataload(0x9e0), f_q)) +mstore(0xc80, mod(calldataload(0xa00), f_q)) +mstore(0xca0, mod(calldataload(0xa20), f_q)) +mstore(0xcc0, mod(calldataload(0xa40), f_q)) +mstore(0xce0, mod(calldataload(0xa60), f_q)) +mstore(0xd00, mod(calldataload(0xa80), f_q)) +mstore(0xd20, keccak256(0xaa0, 640)) +{ + let hash := mload(0xd20) + mstore(0xd40, mod(hash, f_q)) + mstore(0xd60, hash) + } +mstore8(3456, 1) +mstore(0xd80, keccak256(0xd60, 33)) +{ + let hash := mload(0xd80) + mstore(0xda0, mod(hash, f_q)) + mstore(0xdc0, hash) + } + + { + let x := calldataload(0xaa0) + mstore(0xde0, x) + let y := calldataload(0xac0) + mstore(0xe00, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xe20, keccak256(0xdc0, 96)) +{ + let hash := mload(0xe20) + mstore(0xe40, mod(hash, f_q)) + mstore(0xe60, hash) + } + + { + let x := calldataload(0xae0) + mstore(0xe80, x) + let y := calldataload(0xb00) + mstore(0xea0, y) + success := and(validate_ec_point(x, y), success) + } +{ + let x := mload(0xa0) +x := add(x, shl(88, mload(0xc0))) +x := add(x, shl(176, mload(0xe0))) +mstore(3776, x) +let y := mload(0x100) +y := add(y, shl(88, mload(0x120))) +y := add(y, shl(176, mload(0x140))) +mstore(3808, y) + + success := and(validate_ec_point(x, y), success) + } +{ + let x := mload(0x160) +x := add(x, shl(88, mload(0x180))) +x := add(x, shl(176, mload(0x1a0))) +mstore(3840, x) +let y := mload(0x1c0) +y := add(y, shl(88, mload(0x1e0))) +y := add(y, shl(176, mload(0x200))) +mstore(3872, y) + + success := and(validate_ec_point(x, y), success) + } +mstore(0xf40, mulmod(mload(0xa80), mload(0xa80), f_q)) +mstore(0xf60, mulmod(mload(0xf40), mload(0xf40), f_q)) +mstore(0xf80, mulmod(mload(0xf60), mload(0xf60), f_q)) +mstore(0xfa0, mulmod(mload(0xf80), mload(0xf80), f_q)) +mstore(0xfc0, mulmod(mload(0xfa0), mload(0xfa0), f_q)) +mstore(0xfe0, mulmod(mload(0xfc0), mload(0xfc0), f_q)) +mstore(0x1000, mulmod(mload(0xfe0), mload(0xfe0), f_q)) +mstore(0x1020, mulmod(mload(0x1000), mload(0x1000), f_q)) +mstore(0x1040, mulmod(mload(0x1020), mload(0x1020), f_q)) +mstore(0x1060, mulmod(mload(0x1040), mload(0x1040), f_q)) +mstore(0x1080, mulmod(mload(0x1060), mload(0x1060), f_q)) +mstore(0x10a0, mulmod(mload(0x1080), mload(0x1080), f_q)) +mstore(0x10c0, mulmod(mload(0x10a0), mload(0x10a0), f_q)) +mstore(0x10e0, mulmod(mload(0x10c0), mload(0x10c0), f_q)) +mstore(0x1100, mulmod(mload(0x10e0), mload(0x10e0), f_q)) +mstore(0x1120, mulmod(mload(0x1100), mload(0x1100), f_q)) +mstore(0x1140, mulmod(mload(0x1120), mload(0x1120), f_q)) +mstore(0x1160, mulmod(mload(0x1140), mload(0x1140), f_q)) +mstore(0x1180, mulmod(mload(0x1160), mload(0x1160), f_q)) +mstore(0x11a0, mulmod(mload(0x1180), mload(0x1180), f_q)) +mstore(0x11c0, mulmod(mload(0x11a0), mload(0x11a0), f_q)) +mstore(0x11e0, mulmod(mload(0x11c0), mload(0x11c0), f_q)) +mstore(0x1200, addmod(mload(0x11e0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1220, mulmod(mload(0x1200), 21888237653275510688422624196183639687472264873923820041627027729598873448513, f_q)) +mstore(0x1240, mulmod(mload(0x1220), 13225785879531581993054172815365636627224369411478295502904397545373139154045, f_q)) +mstore(0x1260, addmod(mload(0xa80), 8662456992307693229192232929891638461323994988937738840793806641202669341572, f_q)) +mstore(0x1280, mulmod(mload(0x1220), 10939663269433627367777756708678102241564365262857670666700619874077960926249, f_q)) +mstore(0x12a0, addmod(mload(0xa80), 10948579602405647854468649036579172846983999137558363676997584312497847569368, f_q)) +mstore(0x12c0, mulmod(mload(0x1220), 11016257578652593686382655500910603527869149377564754001549454008164059876499, f_q)) +mstore(0x12e0, addmod(mload(0xa80), 10871985293186681535863750244346671560679215022851280342148750178411748619118, f_q)) +mstore(0x1300, mulmod(mload(0x1220), 15402826414547299628414612080036060696555554914079673875872749760617770134879, f_q)) +mstore(0x1320, addmod(mload(0xa80), 6485416457291975593831793665221214391992809486336360467825454425958038360738, f_q)) +mstore(0x1340, mulmod(mload(0x1220), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q)) +mstore(0x1360, addmod(mload(0xa80), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q)) +mstore(0x1380, mulmod(mload(0x1220), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x13a0, addmod(mload(0xa80), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) +mstore(0x13c0, mulmod(mload(0x1220), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +mstore(0x13e0, addmod(mload(0xa80), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q)) +mstore(0x1400, mulmod(mload(0x1220), 1, f_q)) +mstore(0x1420, addmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1440, mulmod(mload(0x1220), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +mstore(0x1460, addmod(mload(0xa80), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q)) +mstore(0x1480, mulmod(mload(0x1220), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x14a0, addmod(mload(0xa80), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) +mstore(0x14c0, mulmod(mload(0x1220), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +mstore(0x14e0, addmod(mload(0xa80), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q)) +mstore(0x1500, mulmod(mload(0x1220), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x1520, addmod(mload(0xa80), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) +mstore(0x1540, mulmod(mload(0x1220), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q)) +mstore(0x1560, addmod(mload(0xa80), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q)) +mstore(0x1580, mulmod(mload(0x1220), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x15a0, addmod(mload(0xa80), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) +mstore(0x15c0, mulmod(mload(0x1220), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q)) +mstore(0x15e0, addmod(mload(0xa80), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q)) +mstore(0x1600, mulmod(mload(0x1220), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) +mstore(0x1620, addmod(mload(0xa80), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) +mstore(0x1640, mulmod(mload(0x1220), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q)) +mstore(0x1660, addmod(mload(0xa80), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q)) +mstore(0x1680, mulmod(mload(0x1220), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) +mstore(0x16a0, addmod(mload(0xa80), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) +mstore(0x16c0, mulmod(mload(0x1220), 13553911191894110065493137367144919847521088405945523452288398666974237857208, f_q)) +mstore(0x16e0, addmod(mload(0xa80), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q)) +mstore(0x1700, mulmod(mload(0x1220), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) +mstore(0x1720, addmod(mload(0xa80), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) +mstore(0x1740, mulmod(mload(0x1220), 10807735674816066981985242612061336605021639643453679977988966079770672437131, f_q)) +mstore(0x1760, addmod(mload(0xa80), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q)) +mstore(0x1780, mulmod(mload(0x1220), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) +mstore(0x17a0, addmod(mload(0xa80), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) +mstore(0x17c0, mulmod(mload(0x1220), 16038300751658239075779628684257016433412502747804121525056508685985277092575, f_q)) +mstore(0x17e0, addmod(mload(0xa80), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q)) +mstore(0x1800, mulmod(mload(0x1220), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) +mstore(0x1820, addmod(mload(0xa80), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) +mstore(0x1840, mulmod(mload(0x1220), 13498745591877810872211159461644682954739332524336278910448604883789771736885, f_q)) +mstore(0x1860, addmod(mload(0xa80), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q)) +mstore(0x1880, mulmod(mload(0x1220), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) +mstore(0x18a0, addmod(mload(0xa80), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) +mstore(0x18c0, mulmod(mload(0x1220), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q)) +mstore(0x18e0, addmod(mload(0xa80), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q)) +mstore(0x1900, mulmod(mload(0x1220), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) +mstore(0x1920, addmod(mload(0xa80), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) +mstore(0x1940, mulmod(mload(0x1220), 15161189183906287273290738379431332336600234154579306802151507052820126345529, f_q)) +mstore(0x1960, addmod(mload(0xa80), 6727053687932987948955667365825942751948130245836727541546697133755682150088, f_q)) +mstore(0x1980, mulmod(mload(0x1220), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) +mstore(0x19a0, addmod(mload(0xa80), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) +mstore(0x19c0, mulmod(mload(0x1220), 16611719114775828483319365659907682366622074960672212059891361227499450055959, f_q)) +mstore(0x19e0, addmod(mload(0xa80), 5276523757063446738927040085349592721926289439743822283806842959076358439658, f_q)) +mstore(0x1a00, mulmod(mload(0x1220), 4509404676247677387317362072810231899718070082381452255950861037254608304934, f_q)) +mstore(0x1a20, addmod(mload(0xa80), 17378838195591597834929043672447043188830294318034582087747343149321200190683, f_q)) +mstore(0x1a40, mulmod(mload(0x1220), 6866457077948847028333856457654941632900463970069876241424363695212127143359, f_q)) +mstore(0x1a60, addmod(mload(0xa80), 15021785793890428193912549287602333455647900430346158102273840491363681352258, f_q)) +mstore(0x1a80, mulmod(mload(0x1220), 20169013865622130318472103510465966222180994822334426398191891983290742724178, f_q)) +mstore(0x1aa0, addmod(mload(0xa80), 1719229006217144903774302234791308866367369578081607945506312203285065771439, f_q)) +mstore(0x1ac0, mulmod(mload(0x1220), 14874205783542236433261764022044465911656512639684999678853651860683757650009, f_q)) +mstore(0x1ae0, addmod(mload(0xa80), 7014037088297038788984641723212809176891851760731034664844552325892050845608, f_q)) +mstore(0x1b00, mulmod(mload(0x1220), 2579947959091681244170407980400327834520881737801886423874592072501514087543, f_q)) +mstore(0x1b20, addmod(mload(0xa80), 19308294912747593978075997764856947254027482662614147919823612114074294408074, f_q)) +mstore(0x1b40, mulmod(mload(0x1220), 17011225028452114973964561549541821925778010085385130152192105634715080939230, f_q)) +mstore(0x1b60, addmod(mload(0xa80), 4877017843387160248281844195715453162770354315030904191506098551860727556387, f_q)) +mstore(0x1b80, mulmod(mload(0x1220), 1881761935718519990121799628252273658786792458106649887437395059872945867717, f_q)) +mstore(0x1ba0, addmod(mload(0xa80), 20006480936120755232124606117005001429761571942309384456260809126702862627900, f_q)) +mstore(0x1bc0, mulmod(mload(0x1220), 21662285561588145310352318480822402603888953131447478827940284064946709915517, f_q)) +mstore(0x1be0, addmod(mload(0xa80), 225957310251129911894087264434872484659411268968555515757920121629098580100, f_q)) +mstore(0x1c00, mulmod(mload(0x1220), 21846745818185811051373434299876022191132089169516983080959277716660228899818, f_q)) +mstore(0x1c20, addmod(mload(0xa80), 41497053653464170872971445381252897416275230899051262738926469915579595799, f_q)) +mstore(0x1c40, mulmod(mload(0x1220), 11770617947510597378885200406447716404126404817511323735042103519754393416137, f_q)) +mstore(0x1c60, addmod(mload(0xa80), 10117624924328677843361205338809558684421959582904710608656100666821415079480, f_q)) +mstore(0x1c80, mulmod(mload(0x1220), 13018529307372270489258244406856841315962482733096074798317807775255504614069, f_q)) +mstore(0x1ca0, addmod(mload(0xa80), 8869713564467004732988161338400433772585881667319959545380396411320303881548, f_q)) +mstore(0x1cc0, mulmod(mload(0x1220), 5276270562549512946272803945594037128265390012927669941530122528135796334063, f_q)) +mstore(0x1ce0, addmod(mload(0xa80), 16611972309289762275973601799663237960282974387488364402168081658440012161554, f_q)) +mstore(0x1d00, mulmod(mload(0x1220), 1459528961030896569807206253631725410868595642414057264270714861278164633285, f_q)) +mstore(0x1d20, addmod(mload(0xa80), 20428713910808378652439199491625549677679768758001977079427489325297643862332, f_q)) +mstore(0x1d40, mulmod(mload(0x1220), 3194789416964050406424265110350613664596286587119568977604859939037397011192, f_q)) +mstore(0x1d60, addmod(mload(0xa80), 18693453454875224815822140634906661423952077813296465366093344247538411484425, f_q)) +mstore(0x1d80, mulmod(mload(0x1220), 3090451643741879200285099477849831179472024364989630500355756836624424014697, f_q)) +mstore(0x1da0, addmod(mload(0xa80), 18797791228097396021961306267407443909076340035426403843342447349951384480920, f_q)) +mstore(0x1dc0, mulmod(mload(0x1220), 15927748781034921005593027077824543133423706442106451156060388409950986747549, f_q)) +mstore(0x1de0, addmod(mload(0xa80), 5960494090804354216653378667432731955124657958309583187637815776624821748068, f_q)) +mstore(0x1e00, mulmod(mload(0x1220), 21594472933355353940227302948201802990541640451776958309590170926766063614527, f_q)) +mstore(0x1e20, addmod(mload(0xa80), 293769938483921282019102797055472098006723948639076034108033259809744881090, f_q)) +mstore(0x1e40, mulmod(mload(0x1220), 18627493688178473377890450102960302362510276568110871848038317193719995024144, f_q)) +mstore(0x1e60, addmod(mload(0xa80), 3260749183660801844355955642296972726038087832305162495659886992855813471473, f_q)) +mstore(0x1e80, mulmod(mload(0x1220), 15233875724801927436678555222002139405060841628305391430751578735629430475003, f_q)) +mstore(0x1ea0, addmod(mload(0xa80), 6654367147037347785567850523255135683487522772110642912946625450946378020614, f_q)) +mstore(0x1ec0, mulmod(mload(0x1220), 12662796367122493153085459582914902083443981635312477834616629373139110863873, f_q)) +mstore(0x1ee0, addmod(mload(0xa80), 9225446504716782069160946162342373005104382765103556509081574813436697631744, f_q)) +mstore(0x1f00, mulmod(mload(0x1220), 9228489335593836417731216695316971397516686186585289059470421738439643366942, f_q)) +mstore(0x1f20, addmod(mload(0xa80), 12659753536245438804515189049940303691031678213830745284227782448136165128675, f_q)) +mstore(0x1f40, mulmod(mload(0x1220), 6904960663187367776878651408524770307710353971752548687936010869699798414796, f_q)) +mstore(0x1f60, addmod(mload(0xa80), 14983282208651907445367754336732504780838010428663485655762193316876010080821, f_q)) +{ + let prod := mload(0x1260) + + prod := mulmod(mload(0x12a0), prod, f_q) + mstore(0x1f80, prod) + + prod := mulmod(mload(0x12e0), prod, f_q) + mstore(0x1fa0, prod) + + prod := mulmod(mload(0x1320), prod, f_q) + mstore(0x1fc0, prod) + + prod := mulmod(mload(0x1360), prod, f_q) + mstore(0x1fe0, prod) + + prod := mulmod(mload(0x13a0), prod, f_q) + mstore(0x2000, prod) + + prod := mulmod(mload(0x13e0), prod, f_q) + mstore(0x2020, prod) + + prod := mulmod(mload(0x1420), prod, f_q) + mstore(0x2040, prod) + + prod := mulmod(mload(0x1460), prod, f_q) + mstore(0x2060, prod) + + prod := mulmod(mload(0x14a0), prod, f_q) + mstore(0x2080, prod) + + prod := mulmod(mload(0x14e0), prod, f_q) + mstore(0x20a0, prod) + + prod := mulmod(mload(0x1520), prod, f_q) + mstore(0x20c0, prod) + + prod := mulmod(mload(0x1560), prod, f_q) + mstore(0x20e0, prod) + + prod := mulmod(mload(0x15a0), prod, f_q) + mstore(0x2100, prod) + + prod := mulmod(mload(0x15e0), prod, f_q) + mstore(0x2120, prod) + + prod := mulmod(mload(0x1620), prod, f_q) + mstore(0x2140, prod) + + prod := mulmod(mload(0x1660), prod, f_q) + mstore(0x2160, prod) + + prod := mulmod(mload(0x16a0), prod, f_q) + mstore(0x2180, prod) + + prod := mulmod(mload(0x16e0), prod, f_q) + mstore(0x21a0, prod) + + prod := mulmod(mload(0x1720), prod, f_q) + mstore(0x21c0, prod) + + prod := mulmod(mload(0x1760), prod, f_q) + mstore(0x21e0, prod) + + prod := mulmod(mload(0x17a0), prod, f_q) + mstore(0x2200, prod) + + prod := mulmod(mload(0x17e0), prod, f_q) + mstore(0x2220, prod) + + prod := mulmod(mload(0x1820), prod, f_q) + mstore(0x2240, prod) + + prod := mulmod(mload(0x1860), prod, f_q) + mstore(0x2260, prod) + + prod := mulmod(mload(0x18a0), prod, f_q) + mstore(0x2280, prod) + + prod := mulmod(mload(0x18e0), prod, f_q) + mstore(0x22a0, prod) + + prod := mulmod(mload(0x1920), prod, f_q) + mstore(0x22c0, prod) + + prod := mulmod(mload(0x1960), prod, f_q) + mstore(0x22e0, prod) + + prod := mulmod(mload(0x19a0), prod, f_q) + mstore(0x2300, prod) + + prod := mulmod(mload(0x19e0), prod, f_q) + mstore(0x2320, prod) + + prod := mulmod(mload(0x1a20), prod, f_q) + mstore(0x2340, prod) + + prod := mulmod(mload(0x1a60), prod, f_q) + mstore(0x2360, prod) + + prod := mulmod(mload(0x1aa0), prod, f_q) + mstore(0x2380, prod) + + prod := mulmod(mload(0x1ae0), prod, f_q) + mstore(0x23a0, prod) + + prod := mulmod(mload(0x1b20), prod, f_q) + mstore(0x23c0, prod) + + prod := mulmod(mload(0x1b60), prod, f_q) + mstore(0x23e0, prod) + + prod := mulmod(mload(0x1ba0), prod, f_q) + mstore(0x2400, prod) + + prod := mulmod(mload(0x1be0), prod, f_q) + mstore(0x2420, prod) + + prod := mulmod(mload(0x1c20), prod, f_q) + mstore(0x2440, prod) + + prod := mulmod(mload(0x1c60), prod, f_q) + mstore(0x2460, prod) + + prod := mulmod(mload(0x1ca0), prod, f_q) + mstore(0x2480, prod) + + prod := mulmod(mload(0x1ce0), prod, f_q) + mstore(0x24a0, prod) + + prod := mulmod(mload(0x1d20), prod, f_q) + mstore(0x24c0, prod) + + prod := mulmod(mload(0x1d60), prod, f_q) + mstore(0x24e0, prod) + + prod := mulmod(mload(0x1da0), prod, f_q) + mstore(0x2500, prod) + + prod := mulmod(mload(0x1de0), prod, f_q) + mstore(0x2520, prod) + + prod := mulmod(mload(0x1e20), prod, f_q) + mstore(0x2540, prod) + + prod := mulmod(mload(0x1e60), prod, f_q) + mstore(0x2560, prod) + + prod := mulmod(mload(0x1ea0), prod, f_q) + mstore(0x2580, prod) + + prod := mulmod(mload(0x1ee0), prod, f_q) + mstore(0x25a0, prod) + + prod := mulmod(mload(0x1f20), prod, f_q) + mstore(0x25c0, prod) + + prod := mulmod(mload(0x1f60), prod, f_q) + mstore(0x25e0, prod) + + prod := mulmod(mload(0x1200), prod, f_q) + mstore(0x2600, prod) + + } +mstore(0x2640, 32) +mstore(0x2660, 32) +mstore(0x2680, 32) +mstore(0x26a0, mload(0x2600)) +mstore(0x26c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x26e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x2640, 0xc0, 0x2620, 0x20), 1), success) +{ + + let inv := mload(0x2620) + let v + + v := mload(0x1200) + mstore(4608, mulmod(mload(0x25e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f60) + mstore(8032, mulmod(mload(0x25c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f20) + mstore(7968, mulmod(mload(0x25a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ee0) + mstore(7904, mulmod(mload(0x2580), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ea0) + mstore(7840, mulmod(mload(0x2560), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e60) + mstore(7776, mulmod(mload(0x2540), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e20) + mstore(7712, mulmod(mload(0x2520), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1de0) + mstore(7648, mulmod(mload(0x2500), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1da0) + mstore(7584, mulmod(mload(0x24e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d60) + mstore(7520, mulmod(mload(0x24c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d20) + mstore(7456, mulmod(mload(0x24a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ce0) + mstore(7392, mulmod(mload(0x2480), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ca0) + mstore(7328, mulmod(mload(0x2460), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c60) + mstore(7264, mulmod(mload(0x2440), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c20) + mstore(7200, mulmod(mload(0x2420), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1be0) + mstore(7136, mulmod(mload(0x2400), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ba0) + mstore(7072, mulmod(mload(0x23e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b60) + mstore(7008, mulmod(mload(0x23c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b20) + mstore(6944, mulmod(mload(0x23a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ae0) + mstore(6880, mulmod(mload(0x2380), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1aa0) + mstore(6816, mulmod(mload(0x2360), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a60) + mstore(6752, mulmod(mload(0x2340), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a20) + mstore(6688, mulmod(mload(0x2320), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x19e0) + mstore(6624, mulmod(mload(0x2300), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x19a0) + mstore(6560, mulmod(mload(0x22e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1960) + mstore(6496, mulmod(mload(0x22c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1920) + mstore(6432, mulmod(mload(0x22a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x18e0) + mstore(6368, mulmod(mload(0x2280), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x18a0) + mstore(6304, mulmod(mload(0x2260), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1860) + mstore(6240, mulmod(mload(0x2240), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1820) + mstore(6176, mulmod(mload(0x2220), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x17e0) + mstore(6112, mulmod(mload(0x2200), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x17a0) + mstore(6048, mulmod(mload(0x21e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1760) + mstore(5984, mulmod(mload(0x21c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1720) + mstore(5920, mulmod(mload(0x21a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x16e0) + mstore(5856, mulmod(mload(0x2180), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x16a0) + mstore(5792, mulmod(mload(0x2160), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1660) + mstore(5728, mulmod(mload(0x2140), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1620) + mstore(5664, mulmod(mload(0x2120), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x15e0) + mstore(5600, mulmod(mload(0x2100), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x15a0) + mstore(5536, mulmod(mload(0x20e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1560) + mstore(5472, mulmod(mload(0x20c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1520) + mstore(5408, mulmod(mload(0x20a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x14e0) + mstore(5344, mulmod(mload(0x2080), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x14a0) + mstore(5280, mulmod(mload(0x2060), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1460) + mstore(5216, mulmod(mload(0x2040), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1420) + mstore(5152, mulmod(mload(0x2020), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x13e0) + mstore(5088, mulmod(mload(0x2000), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x13a0) + mstore(5024, mulmod(mload(0x1fe0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1360) + mstore(4960, mulmod(mload(0x1fc0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1320) + mstore(4896, mulmod(mload(0x1fa0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x12e0) + mstore(4832, mulmod(mload(0x1f80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x12a0) + mstore(4768, mulmod(mload(0x1260), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x1260, inv) + + } +mstore(0x2700, mulmod(mload(0x1240), mload(0x1260), f_q)) +mstore(0x2720, mulmod(mload(0x1280), mload(0x12a0), f_q)) +mstore(0x2740, mulmod(mload(0x12c0), mload(0x12e0), f_q)) +mstore(0x2760, mulmod(mload(0x1300), mload(0x1320), f_q)) +mstore(0x2780, mulmod(mload(0x1340), mload(0x1360), f_q)) +mstore(0x27a0, mulmod(mload(0x1380), mload(0x13a0), f_q)) +mstore(0x27c0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) +mstore(0x27e0, mulmod(mload(0x1400), mload(0x1420), f_q)) +mstore(0x2800, mulmod(mload(0x1440), mload(0x1460), f_q)) +mstore(0x2820, mulmod(mload(0x1480), mload(0x14a0), f_q)) +mstore(0x2840, mulmod(mload(0x14c0), mload(0x14e0), f_q)) +mstore(0x2860, mulmod(mload(0x1500), mload(0x1520), f_q)) +mstore(0x2880, mulmod(mload(0x1540), mload(0x1560), f_q)) +mstore(0x28a0, mulmod(mload(0x1580), mload(0x15a0), f_q)) +mstore(0x28c0, mulmod(mload(0x15c0), mload(0x15e0), f_q)) +mstore(0x28e0, mulmod(mload(0x1600), mload(0x1620), f_q)) +mstore(0x2900, mulmod(mload(0x1640), mload(0x1660), f_q)) +mstore(0x2920, mulmod(mload(0x1680), mload(0x16a0), f_q)) +mstore(0x2940, mulmod(mload(0x16c0), mload(0x16e0), f_q)) +mstore(0x2960, mulmod(mload(0x1700), mload(0x1720), f_q)) +mstore(0x2980, mulmod(mload(0x1740), mload(0x1760), f_q)) +mstore(0x29a0, mulmod(mload(0x1780), mload(0x17a0), f_q)) +mstore(0x29c0, mulmod(mload(0x17c0), mload(0x17e0), f_q)) +mstore(0x29e0, mulmod(mload(0x1800), mload(0x1820), f_q)) +mstore(0x2a00, mulmod(mload(0x1840), mload(0x1860), f_q)) +mstore(0x2a20, mulmod(mload(0x1880), mload(0x18a0), f_q)) +mstore(0x2a40, mulmod(mload(0x18c0), mload(0x18e0), f_q)) +mstore(0x2a60, mulmod(mload(0x1900), mload(0x1920), f_q)) +mstore(0x2a80, mulmod(mload(0x1940), mload(0x1960), f_q)) +mstore(0x2aa0, mulmod(mload(0x1980), mload(0x19a0), f_q)) +mstore(0x2ac0, mulmod(mload(0x19c0), mload(0x19e0), f_q)) +mstore(0x2ae0, mulmod(mload(0x1a00), mload(0x1a20), f_q)) +mstore(0x2b00, mulmod(mload(0x1a40), mload(0x1a60), f_q)) +mstore(0x2b20, mulmod(mload(0x1a80), mload(0x1aa0), f_q)) +mstore(0x2b40, mulmod(mload(0x1ac0), mload(0x1ae0), f_q)) +mstore(0x2b60, mulmod(mload(0x1b00), mload(0x1b20), f_q)) +mstore(0x2b80, mulmod(mload(0x1b40), mload(0x1b60), f_q)) +mstore(0x2ba0, mulmod(mload(0x1b80), mload(0x1ba0), f_q)) +mstore(0x2bc0, mulmod(mload(0x1bc0), mload(0x1be0), f_q)) +mstore(0x2be0, mulmod(mload(0x1c00), mload(0x1c20), f_q)) +mstore(0x2c00, mulmod(mload(0x1c40), mload(0x1c60), f_q)) +mstore(0x2c20, mulmod(mload(0x1c80), mload(0x1ca0), f_q)) +mstore(0x2c40, mulmod(mload(0x1cc0), mload(0x1ce0), f_q)) +mstore(0x2c60, mulmod(mload(0x1d00), mload(0x1d20), f_q)) +mstore(0x2c80, mulmod(mload(0x1d40), mload(0x1d60), f_q)) +mstore(0x2ca0, mulmod(mload(0x1d80), mload(0x1da0), f_q)) +mstore(0x2cc0, mulmod(mload(0x1dc0), mload(0x1de0), f_q)) +mstore(0x2ce0, mulmod(mload(0x1e00), mload(0x1e20), f_q)) +mstore(0x2d00, mulmod(mload(0x1e40), mload(0x1e60), f_q)) +mstore(0x2d20, mulmod(mload(0x1e80), mload(0x1ea0), f_q)) +mstore(0x2d40, mulmod(mload(0x1ec0), mload(0x1ee0), f_q)) +mstore(0x2d60, mulmod(mload(0x1f00), mload(0x1f20), f_q)) +mstore(0x2d80, mulmod(mload(0x1f40), mload(0x1f60), f_q)) +{ + let result := mulmod(mload(0x27e0), mload(0xa0), f_q) +result := addmod(mulmod(mload(0x2800), mload(0xc0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2820), mload(0xe0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2840), mload(0x100), f_q), result, f_q) +result := addmod(mulmod(mload(0x2860), mload(0x120), f_q), result, f_q) +result := addmod(mulmod(mload(0x2880), mload(0x140), f_q), result, f_q) +result := addmod(mulmod(mload(0x28a0), mload(0x160), f_q), result, f_q) +result := addmod(mulmod(mload(0x28c0), mload(0x180), f_q), result, f_q) +result := addmod(mulmod(mload(0x28e0), mload(0x1a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2900), mload(0x1c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2920), mload(0x1e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2940), mload(0x200), f_q), result, f_q) +result := addmod(mulmod(mload(0x2960), mload(0x220), f_q), result, f_q) +result := addmod(mulmod(mload(0x2980), mload(0x240), f_q), result, f_q) +result := addmod(mulmod(mload(0x29a0), mload(0x260), f_q), result, f_q) +result := addmod(mulmod(mload(0x29c0), mload(0x280), f_q), result, f_q) +result := addmod(mulmod(mload(0x29e0), mload(0x2a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a00), mload(0x2c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a20), mload(0x2e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a40), mload(0x300), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a60), mload(0x320), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a80), mload(0x340), f_q), result, f_q) +result := addmod(mulmod(mload(0x2aa0), mload(0x360), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ac0), mload(0x380), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ae0), mload(0x3a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b00), mload(0x3c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b20), mload(0x3e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b40), mload(0x400), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b60), mload(0x420), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b80), mload(0x440), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ba0), mload(0x460), f_q), result, f_q) +result := addmod(mulmod(mload(0x2bc0), mload(0x480), f_q), result, f_q) +result := addmod(mulmod(mload(0x2be0), mload(0x4a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c00), mload(0x4c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c20), mload(0x4e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c40), mload(0x500), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c60), mload(0x520), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c80), mload(0x540), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ca0), mload(0x560), f_q), result, f_q) +result := addmod(mulmod(mload(0x2cc0), mload(0x580), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ce0), mload(0x5a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d00), mload(0x5c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d20), mload(0x5e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d40), mload(0x600), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d60), mload(0x620), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d80), mload(0x640), f_q), result, f_q) +mstore(11680, result) + } +mstore(0x2dc0, mulmod(mload(0xb00), mload(0xae0), f_q)) +mstore(0x2de0, addmod(mload(0xac0), mload(0x2dc0), f_q)) +mstore(0x2e00, addmod(mload(0x2de0), sub(f_q, mload(0xb20)), f_q)) +mstore(0x2e20, mulmod(mload(0x2e00), mload(0xb80), f_q)) +mstore(0x2e40, mulmod(mload(0x920), mload(0x2e20), f_q)) +mstore(0x2e60, addmod(1, sub(f_q, mload(0xc40)), f_q)) +mstore(0x2e80, mulmod(mload(0x2e60), mload(0x27e0), f_q)) +mstore(0x2ea0, addmod(mload(0x2e40), mload(0x2e80), f_q)) +mstore(0x2ec0, mulmod(mload(0x920), mload(0x2ea0), f_q)) +mstore(0x2ee0, mulmod(mload(0xc40), mload(0xc40), f_q)) +mstore(0x2f00, addmod(mload(0x2ee0), sub(f_q, mload(0xc40)), f_q)) +mstore(0x2f20, mulmod(mload(0x2f00), mload(0x2700), f_q)) +mstore(0x2f40, addmod(mload(0x2ec0), mload(0x2f20), f_q)) +mstore(0x2f60, mulmod(mload(0x920), mload(0x2f40), f_q)) +mstore(0x2f80, addmod(1, sub(f_q, mload(0x2700)), f_q)) +mstore(0x2fa0, addmod(mload(0x2720), mload(0x2740), f_q)) +mstore(0x2fc0, addmod(mload(0x2fa0), mload(0x2760), f_q)) +mstore(0x2fe0, addmod(mload(0x2fc0), mload(0x2780), f_q)) +mstore(0x3000, addmod(mload(0x2fe0), mload(0x27a0), f_q)) +mstore(0x3020, addmod(mload(0x3000), mload(0x27c0), f_q)) +mstore(0x3040, addmod(mload(0x2f80), sub(f_q, mload(0x3020)), f_q)) +mstore(0x3060, mulmod(mload(0xbe0), mload(0x7a0), f_q)) +mstore(0x3080, addmod(mload(0xb40), mload(0x3060), f_q)) +mstore(0x30a0, addmod(mload(0x3080), mload(0x800), f_q)) +mstore(0x30c0, mulmod(mload(0xc00), mload(0x7a0), f_q)) +mstore(0x30e0, addmod(mload(0xac0), mload(0x30c0), f_q)) +mstore(0x3100, addmod(mload(0x30e0), mload(0x800), f_q)) +mstore(0x3120, mulmod(mload(0x3100), mload(0x30a0), f_q)) +mstore(0x3140, mulmod(mload(0xc20), mload(0x7a0), f_q)) +mstore(0x3160, addmod(mload(0x2da0), mload(0x3140), f_q)) +mstore(0x3180, addmod(mload(0x3160), mload(0x800), f_q)) +mstore(0x31a0, mulmod(mload(0x3180), mload(0x3120), f_q)) +mstore(0x31c0, mulmod(mload(0x31a0), mload(0xc60), f_q)) +mstore(0x31e0, mulmod(1, mload(0x7a0), f_q)) +mstore(0x3200, mulmod(mload(0xa80), mload(0x31e0), f_q)) +mstore(0x3220, addmod(mload(0xb40), mload(0x3200), f_q)) +mstore(0x3240, addmod(mload(0x3220), mload(0x800), f_q)) +mstore(0x3260, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x7a0), f_q)) +mstore(0x3280, mulmod(mload(0xa80), mload(0x3260), f_q)) +mstore(0x32a0, addmod(mload(0xac0), mload(0x3280), f_q)) +mstore(0x32c0, addmod(mload(0x32a0), mload(0x800), f_q)) +mstore(0x32e0, mulmod(mload(0x32c0), mload(0x3240), f_q)) +mstore(0x3300, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x7a0), f_q)) +mstore(0x3320, mulmod(mload(0xa80), mload(0x3300), f_q)) +mstore(0x3340, addmod(mload(0x2da0), mload(0x3320), f_q)) +mstore(0x3360, addmod(mload(0x3340), mload(0x800), f_q)) +mstore(0x3380, mulmod(mload(0x3360), mload(0x32e0), f_q)) +mstore(0x33a0, mulmod(mload(0x3380), mload(0xc40), f_q)) +mstore(0x33c0, addmod(mload(0x31c0), sub(f_q, mload(0x33a0)), f_q)) +mstore(0x33e0, mulmod(mload(0x33c0), mload(0x3040), f_q)) +mstore(0x3400, addmod(mload(0x2f60), mload(0x33e0), f_q)) +mstore(0x3420, mulmod(mload(0x920), mload(0x3400), f_q)) +mstore(0x3440, addmod(1, sub(f_q, mload(0xc80)), f_q)) +mstore(0x3460, mulmod(mload(0x3440), mload(0x27e0), f_q)) +mstore(0x3480, addmod(mload(0x3420), mload(0x3460), f_q)) +mstore(0x34a0, mulmod(mload(0x920), mload(0x3480), f_q)) +mstore(0x34c0, mulmod(mload(0xc80), mload(0xc80), f_q)) +mstore(0x34e0, addmod(mload(0x34c0), sub(f_q, mload(0xc80)), f_q)) +mstore(0x3500, mulmod(mload(0x34e0), mload(0x2700), f_q)) +mstore(0x3520, addmod(mload(0x34a0), mload(0x3500), f_q)) +mstore(0x3540, mulmod(mload(0x920), mload(0x3520), f_q)) +mstore(0x3560, addmod(mload(0xcc0), mload(0x7a0), f_q)) +mstore(0x3580, mulmod(mload(0x3560), mload(0xca0), f_q)) +mstore(0x35a0, addmod(mload(0xd00), mload(0x800), f_q)) +mstore(0x35c0, mulmod(mload(0x35a0), mload(0x3580), f_q)) +mstore(0x35e0, mulmod(mload(0xac0), mload(0xba0), f_q)) +mstore(0x3600, addmod(mload(0x35e0), mload(0x7a0), f_q)) +mstore(0x3620, mulmod(mload(0x3600), mload(0xc80), f_q)) +mstore(0x3640, addmod(mload(0xb60), mload(0x800), f_q)) +mstore(0x3660, mulmod(mload(0x3640), mload(0x3620), f_q)) +mstore(0x3680, addmod(mload(0x35c0), sub(f_q, mload(0x3660)), f_q)) +mstore(0x36a0, mulmod(mload(0x3680), mload(0x3040), f_q)) +mstore(0x36c0, addmod(mload(0x3540), mload(0x36a0), f_q)) +mstore(0x36e0, mulmod(mload(0x920), mload(0x36c0), f_q)) +mstore(0x3700, addmod(mload(0xcc0), sub(f_q, mload(0xd00)), f_q)) +mstore(0x3720, mulmod(mload(0x3700), mload(0x27e0), f_q)) +mstore(0x3740, addmod(mload(0x36e0), mload(0x3720), f_q)) +mstore(0x3760, mulmod(mload(0x920), mload(0x3740), f_q)) +mstore(0x3780, mulmod(mload(0x3700), mload(0x3040), f_q)) +mstore(0x37a0, addmod(mload(0xcc0), sub(f_q, mload(0xce0)), f_q)) +mstore(0x37c0, mulmod(mload(0x37a0), mload(0x3780), f_q)) +mstore(0x37e0, addmod(mload(0x3760), mload(0x37c0), f_q)) +mstore(0x3800, mulmod(mload(0x11e0), mload(0x11e0), f_q)) +mstore(0x3820, mulmod(mload(0x3800), mload(0x11e0), f_q)) +mstore(0x3840, mulmod(mload(0x3820), mload(0x11e0), f_q)) +mstore(0x3860, mulmod(1, mload(0x11e0), f_q)) +mstore(0x3880, mulmod(1, mload(0x3800), f_q)) +mstore(0x38a0, mulmod(1, mload(0x3820), f_q)) +mstore(0x38c0, mulmod(mload(0x37e0), mload(0x1200), f_q)) +mstore(0x38e0, mulmod(mload(0xf40), mload(0xa80), f_q)) +mstore(0x3900, mulmod(mload(0x38e0), mload(0xa80), f_q)) +mstore(0x3920, mulmod(mload(0xa80), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +mstore(0x3940, addmod(mload(0xe40), sub(f_q, mload(0x3920)), f_q)) +mstore(0x3960, mulmod(mload(0xa80), 1, f_q)) +mstore(0x3980, addmod(mload(0xe40), sub(f_q, mload(0x3960)), f_q)) +mstore(0x39a0, mulmod(mload(0xa80), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +mstore(0x39c0, addmod(mload(0xe40), sub(f_q, mload(0x39a0)), f_q)) +mstore(0x39e0, mulmod(mload(0xa80), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x3a00, addmod(mload(0xe40), sub(f_q, mload(0x39e0)), f_q)) +mstore(0x3a20, mulmod(mload(0xa80), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +mstore(0x3a40, addmod(mload(0xe40), sub(f_q, mload(0x3a20)), f_q)) +mstore(0x3a60, mulmod(3544324119167359571073009690693121464267965232733679586767649244433889388945, mload(0x38e0), f_q)) +mstore(0x3a80, mulmod(mload(0x3a60), 1, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3a60), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3a80)), f_q), result, f_q) +mstore(15008, result) + } +mstore(0x3ac0, mulmod(3860370625838117017501327045244227871206764201116468958063324100051382735289, mload(0x38e0), f_q)) +mstore(0x3ae0, mulmod(mload(0x3ac0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3ac0), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ae0)), f_q), result, f_q) +mstore(15104, result) + } +mstore(0x3b20, mulmod(21616901807277407275624036604424346159916096890712898844034238973395610537327, mload(0x38e0), f_q)) +mstore(0x3b40, mulmod(mload(0x3b20), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3b20), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b40)), f_q), result, f_q) +mstore(15200, result) + } +mstore(0x3b80, mulmod(3209408481237076479025468386201293941554240476766691830436732310949352383503, mload(0x38e0), f_q)) +mstore(0x3ba0, mulmod(mload(0x3b80), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3b80), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ba0)), f_q), result, f_q) +mstore(15296, result) + } +mstore(0x3be0, mulmod(1, mload(0x3980), f_q)) +mstore(0x3c00, mulmod(mload(0x3be0), mload(0x39c0), f_q)) +mstore(0x3c20, mulmod(mload(0x3c00), mload(0x3a00), f_q)) +mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3a40), f_q)) +mstore(0x3c60, mulmod(10676941854703594198666993839846402519342119846958189386823924046696287912228, mload(0xa80), f_q)) +mstore(0x3c80, mulmod(mload(0x3c60), 1, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3c60), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3c80)), f_q), result, f_q) +mstore(15520, result) + } +mstore(0x3cc0, mulmod(11211301017135681023579411905410872569206244553457844956874280139879520583389, mload(0xa80), f_q)) +mstore(0x3ce0, mulmod(mload(0x3cc0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3cc0), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ce0)), f_q), result, f_q) +mstore(15616, result) + } +mstore(0x3d20, mulmod(13154116519010929542673167886091370382741775939114889923107781597533678454430, mload(0xa80), f_q)) +mstore(0x3d40, mulmod(mload(0x3d20), 1, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3d20), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d40)), f_q), result, f_q) +mstore(15712, result) + } +mstore(0x3d80, mulmod(8734126352828345679573237859165904705806588461301144420590422589042130041187, mload(0xa80), f_q)) +mstore(0x3da0, mulmod(mload(0x3d80), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3d80), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3da0)), f_q), result, f_q) +mstore(15808, result) + } +mstore(0x3de0, mulmod(mload(0x3be0), mload(0x3940), f_q)) +{ + let result := mulmod(mload(0xe40), 1, f_q) +result := addmod(mulmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) +mstore(15872, result) + } +{ + let prod := mload(0x3aa0) + + prod := mulmod(mload(0x3b00), prod, f_q) + mstore(0x3e20, prod) + + prod := mulmod(mload(0x3b60), prod, f_q) + mstore(0x3e40, prod) + + prod := mulmod(mload(0x3bc0), prod, f_q) + mstore(0x3e60, prod) + + prod := mulmod(mload(0x3ca0), prod, f_q) + mstore(0x3e80, prod) + + prod := mulmod(mload(0x3d00), prod, f_q) + mstore(0x3ea0, prod) + + prod := mulmod(mload(0x3c00), prod, f_q) + mstore(0x3ec0, prod) + + prod := mulmod(mload(0x3d60), prod, f_q) + mstore(0x3ee0, prod) + + prod := mulmod(mload(0x3dc0), prod, f_q) + mstore(0x3f00, prod) + + prod := mulmod(mload(0x3de0), prod, f_q) + mstore(0x3f20, prod) + + prod := mulmod(mload(0x3e00), prod, f_q) + mstore(0x3f40, prod) + + prod := mulmod(mload(0x3be0), prod, f_q) + mstore(0x3f60, prod) + + } +mstore(0x3fa0, 32) +mstore(0x3fc0, 32) +mstore(0x3fe0, 32) +mstore(0x4000, mload(0x3f60)) +mstore(0x4020, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x4040, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x3fa0, 0xc0, 0x3f80, 0x20), 1), success) +{ + + let inv := mload(0x3f80) + let v + + v := mload(0x3be0) + mstore(15328, mulmod(mload(0x3f40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3e00) + mstore(15872, mulmod(mload(0x3f20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3de0) + mstore(15840, mulmod(mload(0x3f00), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3dc0) + mstore(15808, mulmod(mload(0x3ee0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3d60) + mstore(15712, mulmod(mload(0x3ec0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3c00) + mstore(15360, mulmod(mload(0x3ea0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3d00) + mstore(15616, mulmod(mload(0x3e80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3ca0) + mstore(15520, mulmod(mload(0x3e60), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3bc0) + mstore(15296, mulmod(mload(0x3e40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3b60) + mstore(15200, mulmod(mload(0x3e20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3b00) + mstore(15104, mulmod(mload(0x3aa0), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x3aa0, inv) + + } +{ + let result := mload(0x3aa0) +result := addmod(mload(0x3b00), result, f_q) +result := addmod(mload(0x3b60), result, f_q) +result := addmod(mload(0x3bc0), result, f_q) +mstore(16480, result) + } +mstore(0x4080, mulmod(mload(0x3c40), mload(0x3c00), f_q)) +{ + let result := mload(0x3ca0) +result := addmod(mload(0x3d00), result, f_q) +mstore(16544, result) + } +mstore(0x40c0, mulmod(mload(0x3c40), mload(0x3de0), f_q)) +{ + let result := mload(0x3d60) +result := addmod(mload(0x3dc0), result, f_q) +mstore(16608, result) + } +mstore(0x4100, mulmod(mload(0x3c40), mload(0x3be0), f_q)) +{ + let result := mload(0x3e00) +mstore(16672, result) + } +{ + let prod := mload(0x4060) + + prod := mulmod(mload(0x40a0), prod, f_q) + mstore(0x4140, prod) + + prod := mulmod(mload(0x40e0), prod, f_q) + mstore(0x4160, prod) + + prod := mulmod(mload(0x4120), prod, f_q) + mstore(0x4180, prod) + + } +mstore(0x41c0, 32) +mstore(0x41e0, 32) +mstore(0x4200, 32) +mstore(0x4220, mload(0x4180)) +mstore(0x4240, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x4260, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x41c0, 0xc0, 0x41a0, 0x20), 1), success) +{ + + let inv := mload(0x41a0) + let v + + v := mload(0x4120) + mstore(16672, mulmod(mload(0x4160), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x40e0) + mstore(16608, mulmod(mload(0x4140), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x40a0) + mstore(16544, mulmod(mload(0x4060), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x4060, inv) + + } +mstore(0x4280, mulmod(mload(0x4080), mload(0x40a0), f_q)) +mstore(0x42a0, mulmod(mload(0x40c0), mload(0x40e0), f_q)) +mstore(0x42c0, mulmod(mload(0x4100), mload(0x4120), f_q)) +mstore(0x42e0, mulmod(mload(0xd40), mload(0xd40), f_q)) +mstore(0x4300, mulmod(mload(0x42e0), mload(0xd40), f_q)) +mstore(0x4320, mulmod(mload(0x4300), mload(0xd40), f_q)) +mstore(0x4340, mulmod(mload(0x4320), mload(0xd40), f_q)) +mstore(0x4360, mulmod(mload(0x4340), mload(0xd40), f_q)) +mstore(0x4380, mulmod(mload(0x4360), mload(0xd40), f_q)) +mstore(0x43a0, mulmod(mload(0x4380), mload(0xd40), f_q)) +mstore(0x43c0, mulmod(mload(0x43a0), mload(0xd40), f_q)) +mstore(0x43e0, mulmod(mload(0x43c0), mload(0xd40), f_q)) +mstore(0x4400, mulmod(mload(0xda0), mload(0xda0), f_q)) +mstore(0x4420, mulmod(mload(0x4400), mload(0xda0), f_q)) +mstore(0x4440, mulmod(mload(0x4420), mload(0xda0), f_q)) +{ + let result := mulmod(mload(0xac0), mload(0x3aa0), f_q) +result := addmod(mulmod(mload(0xae0), mload(0x3b00), f_q), result, f_q) +result := addmod(mulmod(mload(0xb00), mload(0x3b60), f_q), result, f_q) +result := addmod(mulmod(mload(0xb20), mload(0x3bc0), f_q), result, f_q) +mstore(17504, result) + } +mstore(0x4480, mulmod(mload(0x4460), mload(0x4060), f_q)) +mstore(0x44a0, mulmod(sub(f_q, mload(0x4480)), 1, f_q)) +mstore(0x44c0, mulmod(mload(0x44a0), 1, f_q)) +mstore(0x44e0, mulmod(1, mload(0x4080), f_q)) +{ + let result := mulmod(mload(0xc40), mload(0x3ca0), f_q) +result := addmod(mulmod(mload(0xc60), mload(0x3d00), f_q), result, f_q) +mstore(17664, result) + } +mstore(0x4520, mulmod(mload(0x4500), mload(0x4280), f_q)) +mstore(0x4540, mulmod(sub(f_q, mload(0x4520)), 1, f_q)) +mstore(0x4560, mulmod(mload(0x44e0), 1, f_q)) +{ + let result := mulmod(mload(0xc80), mload(0x3ca0), f_q) +result := addmod(mulmod(mload(0xca0), mload(0x3d00), f_q), result, f_q) +mstore(17792, result) + } +mstore(0x45a0, mulmod(mload(0x4580), mload(0x4280), f_q)) +mstore(0x45c0, mulmod(sub(f_q, mload(0x45a0)), mload(0xd40), f_q)) +mstore(0x45e0, mulmod(mload(0x44e0), mload(0xd40), f_q)) +mstore(0x4600, addmod(mload(0x4540), mload(0x45c0), f_q)) +mstore(0x4620, mulmod(mload(0x4600), mload(0xda0), f_q)) +mstore(0x4640, mulmod(mload(0x4560), mload(0xda0), f_q)) +mstore(0x4660, mulmod(mload(0x45e0), mload(0xda0), f_q)) +mstore(0x4680, addmod(mload(0x44c0), mload(0x4620), f_q)) +mstore(0x46a0, mulmod(1, mload(0x40c0), f_q)) +{ + let result := mulmod(mload(0xcc0), mload(0x3d60), f_q) +result := addmod(mulmod(mload(0xce0), mload(0x3dc0), f_q), result, f_q) +mstore(18112, result) + } +mstore(0x46e0, mulmod(mload(0x46c0), mload(0x42a0), f_q)) +mstore(0x4700, mulmod(sub(f_q, mload(0x46e0)), 1, f_q)) +mstore(0x4720, mulmod(mload(0x46a0), 1, f_q)) +mstore(0x4740, mulmod(mload(0x4700), mload(0x4400), f_q)) +mstore(0x4760, mulmod(mload(0x4720), mload(0x4400), f_q)) +mstore(0x4780, addmod(mload(0x4680), mload(0x4740), f_q)) +mstore(0x47a0, mulmod(1, mload(0x4100), f_q)) +{ + let result := mulmod(mload(0xd00), mload(0x3e00), f_q) +mstore(18368, result) + } +mstore(0x47e0, mulmod(mload(0x47c0), mload(0x42c0), f_q)) +mstore(0x4800, mulmod(sub(f_q, mload(0x47e0)), 1, f_q)) +mstore(0x4820, mulmod(mload(0x47a0), 1, f_q)) +{ + let result := mulmod(mload(0xb40), mload(0x3e00), f_q) +mstore(18496, result) + } +mstore(0x4860, mulmod(mload(0x4840), mload(0x42c0), f_q)) +mstore(0x4880, mulmod(sub(f_q, mload(0x4860)), mload(0xd40), f_q)) +mstore(0x48a0, mulmod(mload(0x47a0), mload(0xd40), f_q)) +mstore(0x48c0, addmod(mload(0x4800), mload(0x4880), f_q)) +{ + let result := mulmod(mload(0xb60), mload(0x3e00), f_q) +mstore(18656, result) + } +mstore(0x4900, mulmod(mload(0x48e0), mload(0x42c0), f_q)) +mstore(0x4920, mulmod(sub(f_q, mload(0x4900)), mload(0x42e0), f_q)) +mstore(0x4940, mulmod(mload(0x47a0), mload(0x42e0), f_q)) +mstore(0x4960, addmod(mload(0x48c0), mload(0x4920), f_q)) +{ + let result := mulmod(mload(0xb80), mload(0x3e00), f_q) +mstore(18816, result) + } +mstore(0x49a0, mulmod(mload(0x4980), mload(0x42c0), f_q)) +mstore(0x49c0, mulmod(sub(f_q, mload(0x49a0)), mload(0x4300), f_q)) +mstore(0x49e0, mulmod(mload(0x47a0), mload(0x4300), f_q)) +mstore(0x4a00, addmod(mload(0x4960), mload(0x49c0), f_q)) +{ + let result := mulmod(mload(0xba0), mload(0x3e00), f_q) +mstore(18976, result) + } +mstore(0x4a40, mulmod(mload(0x4a20), mload(0x42c0), f_q)) +mstore(0x4a60, mulmod(sub(f_q, mload(0x4a40)), mload(0x4320), f_q)) +mstore(0x4a80, mulmod(mload(0x47a0), mload(0x4320), f_q)) +mstore(0x4aa0, addmod(mload(0x4a00), mload(0x4a60), f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x3e00), f_q) +mstore(19136, result) + } +mstore(0x4ae0, mulmod(mload(0x4ac0), mload(0x42c0), f_q)) +mstore(0x4b00, mulmod(sub(f_q, mload(0x4ae0)), mload(0x4340), f_q)) +mstore(0x4b20, mulmod(mload(0x47a0), mload(0x4340), f_q)) +mstore(0x4b40, addmod(mload(0x4aa0), mload(0x4b00), f_q)) +{ + let result := mulmod(mload(0xc00), mload(0x3e00), f_q) +mstore(19296, result) + } +mstore(0x4b80, mulmod(mload(0x4b60), mload(0x42c0), f_q)) +mstore(0x4ba0, mulmod(sub(f_q, mload(0x4b80)), mload(0x4360), f_q)) +mstore(0x4bc0, mulmod(mload(0x47a0), mload(0x4360), f_q)) +mstore(0x4be0, addmod(mload(0x4b40), mload(0x4ba0), f_q)) +{ + let result := mulmod(mload(0xc20), mload(0x3e00), f_q) +mstore(19456, result) + } +mstore(0x4c20, mulmod(mload(0x4c00), mload(0x42c0), f_q)) +mstore(0x4c40, mulmod(sub(f_q, mload(0x4c20)), mload(0x4380), f_q)) +mstore(0x4c60, mulmod(mload(0x47a0), mload(0x4380), f_q)) +mstore(0x4c80, addmod(mload(0x4be0), mload(0x4c40), f_q)) +mstore(0x4ca0, mulmod(mload(0x3860), mload(0x4100), f_q)) +mstore(0x4cc0, mulmod(mload(0x3880), mload(0x4100), f_q)) +mstore(0x4ce0, mulmod(mload(0x38a0), mload(0x4100), f_q)) +{ + let result := mulmod(mload(0x38c0), mload(0x3e00), f_q) +mstore(19712, result) + } +mstore(0x4d20, mulmod(mload(0x4d00), mload(0x42c0), f_q)) +mstore(0x4d40, mulmod(sub(f_q, mload(0x4d20)), mload(0x43a0), f_q)) +mstore(0x4d60, mulmod(mload(0x47a0), mload(0x43a0), f_q)) +mstore(0x4d80, mulmod(mload(0x4ca0), mload(0x43a0), f_q)) +mstore(0x4da0, mulmod(mload(0x4cc0), mload(0x43a0), f_q)) +mstore(0x4dc0, mulmod(mload(0x4ce0), mload(0x43a0), f_q)) +mstore(0x4de0, addmod(mload(0x4c80), mload(0x4d40), f_q)) +{ + let result := mulmod(mload(0xbc0), mload(0x3e00), f_q) +mstore(19968, result) + } +mstore(0x4e20, mulmod(mload(0x4e00), mload(0x42c0), f_q)) +mstore(0x4e40, mulmod(sub(f_q, mload(0x4e20)), mload(0x43c0), f_q)) +mstore(0x4e60, mulmod(mload(0x47a0), mload(0x43c0), f_q)) +mstore(0x4e80, addmod(mload(0x4de0), mload(0x4e40), f_q)) +mstore(0x4ea0, mulmod(mload(0x4e80), mload(0x4420), f_q)) +mstore(0x4ec0, mulmod(mload(0x4820), mload(0x4420), f_q)) +mstore(0x4ee0, mulmod(mload(0x48a0), mload(0x4420), f_q)) +mstore(0x4f00, mulmod(mload(0x4940), mload(0x4420), f_q)) +mstore(0x4f20, mulmod(mload(0x49e0), mload(0x4420), f_q)) +mstore(0x4f40, mulmod(mload(0x4a80), mload(0x4420), f_q)) +mstore(0x4f60, mulmod(mload(0x4b20), mload(0x4420), f_q)) +mstore(0x4f80, mulmod(mload(0x4bc0), mload(0x4420), f_q)) +mstore(0x4fa0, mulmod(mload(0x4c60), mload(0x4420), f_q)) +mstore(0x4fc0, mulmod(mload(0x4d60), mload(0x4420), f_q)) +mstore(0x4fe0, mulmod(mload(0x4d80), mload(0x4420), f_q)) +mstore(0x5000, mulmod(mload(0x4da0), mload(0x4420), f_q)) +mstore(0x5020, mulmod(mload(0x4dc0), mload(0x4420), f_q)) +mstore(0x5040, mulmod(mload(0x4e60), mload(0x4420), f_q)) +mstore(0x5060, addmod(mload(0x4780), mload(0x4ea0), f_q)) +mstore(0x5080, mulmod(1, mload(0x3c40), f_q)) +mstore(0x50a0, mulmod(1, mload(0xe40), f_q)) +mstore(0x50c0, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x50e0, 0x0000000000000000000000000000000000000000000000000000000000000002) +mstore(0x5100, mload(0x5060)) +success := and(eq(staticcall(gas(), 0x7, 0x50c0, 0x60, 0x50c0, 0x40), 1), success) +mstore(0x5120, mload(0x50c0)) + mstore(0x5140, mload(0x50e0)) +mstore(0x5160, mload(0x660)) + mstore(0x5180, mload(0x680)) +success := and(eq(staticcall(gas(), 0x6, 0x5120, 0x80, 0x5120, 0x40), 1), success) +mstore(0x51a0, mload(0x840)) + mstore(0x51c0, mload(0x860)) +mstore(0x51e0, mload(0x4640)) +success := and(eq(staticcall(gas(), 0x7, 0x51a0, 0x60, 0x51a0, 0x40), 1), success) +mstore(0x5200, mload(0x5120)) + mstore(0x5220, mload(0x5140)) +mstore(0x5240, mload(0x51a0)) + mstore(0x5260, mload(0x51c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5200, 0x80, 0x5200, 0x40), 1), success) +mstore(0x5280, mload(0x880)) + mstore(0x52a0, mload(0x8a0)) +mstore(0x52c0, mload(0x4660)) +success := and(eq(staticcall(gas(), 0x7, 0x5280, 0x60, 0x5280, 0x40), 1), success) +mstore(0x52e0, mload(0x5200)) + mstore(0x5300, mload(0x5220)) +mstore(0x5320, mload(0x5280)) + mstore(0x5340, mload(0x52a0)) +success := and(eq(staticcall(gas(), 0x6, 0x52e0, 0x80, 0x52e0, 0x40), 1), success) +mstore(0x5360, mload(0x700)) + mstore(0x5380, mload(0x720)) +mstore(0x53a0, mload(0x4760)) +success := and(eq(staticcall(gas(), 0x7, 0x5360, 0x60, 0x5360, 0x40), 1), success) +mstore(0x53c0, mload(0x52e0)) + mstore(0x53e0, mload(0x5300)) +mstore(0x5400, mload(0x5360)) + mstore(0x5420, mload(0x5380)) +success := and(eq(staticcall(gas(), 0x6, 0x53c0, 0x80, 0x53c0, 0x40), 1), success) +mstore(0x5440, mload(0x740)) + mstore(0x5460, mload(0x760)) +mstore(0x5480, mload(0x4ec0)) +success := and(eq(staticcall(gas(), 0x7, 0x5440, 0x60, 0x5440, 0x40), 1), success) +mstore(0x54a0, mload(0x53c0)) + mstore(0x54c0, mload(0x53e0)) +mstore(0x54e0, mload(0x5440)) + mstore(0x5500, mload(0x5460)) +success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) +mstore(0x5520, 0x2dc3c1b9bc2ea2927a6676f638518e06a6710821938d21f21f826a74e2df8e08) + mstore(0x5540, 0x1f3430811fcc367d5f54d03de701b5daa7a3d8c14e715cb57eabbcb949261d5f) +mstore(0x5560, mload(0x4ee0)) +success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) +mstore(0x5580, mload(0x54a0)) + mstore(0x55a0, mload(0x54c0)) +mstore(0x55c0, mload(0x5520)) + mstore(0x55e0, mload(0x5540)) +success := and(eq(staticcall(gas(), 0x6, 0x5580, 0x80, 0x5580, 0x40), 1), success) +mstore(0x5600, 0x21c6ea7d6dbcd767ffb9d9beeb4f9c2f8243bc65290f2d75a59aea4f65ba8f3d) + mstore(0x5620, 0x24d0a0acb031c9a5687da08cdaf96650aae5c60435739bda8bbd574eb962622c) +mstore(0x5640, mload(0x4f00)) +success := and(eq(staticcall(gas(), 0x7, 0x5600, 0x60, 0x5600, 0x40), 1), success) +mstore(0x5660, mload(0x5580)) + mstore(0x5680, mload(0x55a0)) +mstore(0x56a0, mload(0x5600)) + mstore(0x56c0, mload(0x5620)) +success := and(eq(staticcall(gas(), 0x6, 0x5660, 0x80, 0x5660, 0x40), 1), success) +mstore(0x56e0, 0x0cd9800e93a11616f9a6d57f5bc8f25b67f6db79ba80cba05a3d14702040dcdf) + mstore(0x5700, 0x2dc617dc6edd82b00f68665fffd95b180fea2a3760e401813cbc178c4ef68a68) +mstore(0x5720, mload(0x4f20)) +success := and(eq(staticcall(gas(), 0x7, 0x56e0, 0x60, 0x56e0, 0x40), 1), success) +mstore(0x5740, mload(0x5660)) + mstore(0x5760, mload(0x5680)) +mstore(0x5780, mload(0x56e0)) + mstore(0x57a0, mload(0x5700)) +success := and(eq(staticcall(gas(), 0x6, 0x5740, 0x80, 0x5740, 0x40), 1), success) +mstore(0x57c0, 0x03959e547f919a0259b2e9d9c77a7213739044a14d6417c327fb28c3bc9ee271) + mstore(0x57e0, 0x1bc7c38f239c6826efe5fe89431fbaa11c65c516f004551ff5fc8048b21c7ae0) +mstore(0x5800, mload(0x4f40)) +success := and(eq(staticcall(gas(), 0x7, 0x57c0, 0x60, 0x57c0, 0x40), 1), success) +mstore(0x5820, mload(0x5740)) + mstore(0x5840, mload(0x5760)) +mstore(0x5860, mload(0x57c0)) + mstore(0x5880, mload(0x57e0)) +success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) +mstore(0x58a0, 0x2025edbb2ccedbde503fb0e916f46a4612168a34387d3779638be4d3f0e583fe) + mstore(0x58c0, 0x28d7541be8b364bd7b9dc7a3c8d8a96c4d13b3344b2c30e1f1634ece387e994e) +mstore(0x58e0, mload(0x4f60)) +success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) +mstore(0x5900, mload(0x5820)) + mstore(0x5920, mload(0x5840)) +mstore(0x5940, mload(0x58a0)) + mstore(0x5960, mload(0x58c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) +mstore(0x5980, 0x11b54f0976d5fc08ec4deed8f5267cbb13f7dd56ee02902e258db064ec2a4d2e) + mstore(0x59a0, 0x2d1cd6dc1209909ec8aae309b36cc453c02e85940cf663a98ba51c5f768cf804) +mstore(0x59c0, mload(0x4f80)) +success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) +mstore(0x59e0, mload(0x5900)) + mstore(0x5a00, mload(0x5920)) +mstore(0x5a20, mload(0x5980)) + mstore(0x5a40, mload(0x59a0)) +success := and(eq(staticcall(gas(), 0x6, 0x59e0, 0x80, 0x59e0, 0x40), 1), success) +mstore(0x5a60, 0x07cae097ef3949f8f3a3fc8926173409851625586e2daf025f17f445c8bbce4f) + mstore(0x5a80, 0x2ffdcf8c6b36fcd21e78f8dc0dd1983aa3b970aaaad4285516afa74bf9511b07) +mstore(0x5aa0, mload(0x4fa0)) +success := and(eq(staticcall(gas(), 0x7, 0x5a60, 0x60, 0x5a60, 0x40), 1), success) +mstore(0x5ac0, mload(0x59e0)) + mstore(0x5ae0, mload(0x5a00)) +mstore(0x5b00, mload(0x5a60)) + mstore(0x5b20, mload(0x5a80)) +success := and(eq(staticcall(gas(), 0x6, 0x5ac0, 0x80, 0x5ac0, 0x40), 1), success) +mstore(0x5b40, mload(0x960)) + mstore(0x5b60, mload(0x980)) +mstore(0x5b80, mload(0x4fc0)) +success := and(eq(staticcall(gas(), 0x7, 0x5b40, 0x60, 0x5b40, 0x40), 1), success) +mstore(0x5ba0, mload(0x5ac0)) + mstore(0x5bc0, mload(0x5ae0)) +mstore(0x5be0, mload(0x5b40)) + mstore(0x5c00, mload(0x5b60)) +success := and(eq(staticcall(gas(), 0x6, 0x5ba0, 0x80, 0x5ba0, 0x40), 1), success) +mstore(0x5c20, mload(0x9a0)) + mstore(0x5c40, mload(0x9c0)) +mstore(0x5c60, mload(0x4fe0)) +success := and(eq(staticcall(gas(), 0x7, 0x5c20, 0x60, 0x5c20, 0x40), 1), success) +mstore(0x5c80, mload(0x5ba0)) + mstore(0x5ca0, mload(0x5bc0)) +mstore(0x5cc0, mload(0x5c20)) + mstore(0x5ce0, mload(0x5c40)) +success := and(eq(staticcall(gas(), 0x6, 0x5c80, 0x80, 0x5c80, 0x40), 1), success) +mstore(0x5d00, mload(0x9e0)) + mstore(0x5d20, mload(0xa00)) +mstore(0x5d40, mload(0x5000)) +success := and(eq(staticcall(gas(), 0x7, 0x5d00, 0x60, 0x5d00, 0x40), 1), success) +mstore(0x5d60, mload(0x5c80)) + mstore(0x5d80, mload(0x5ca0)) +mstore(0x5da0, mload(0x5d00)) + mstore(0x5dc0, mload(0x5d20)) +success := and(eq(staticcall(gas(), 0x6, 0x5d60, 0x80, 0x5d60, 0x40), 1), success) +mstore(0x5de0, mload(0xa20)) + mstore(0x5e00, mload(0xa40)) +mstore(0x5e20, mload(0x5020)) +success := and(eq(staticcall(gas(), 0x7, 0x5de0, 0x60, 0x5de0, 0x40), 1), success) +mstore(0x5e40, mload(0x5d60)) + mstore(0x5e60, mload(0x5d80)) +mstore(0x5e80, mload(0x5de0)) + mstore(0x5ea0, mload(0x5e00)) +success := and(eq(staticcall(gas(), 0x6, 0x5e40, 0x80, 0x5e40, 0x40), 1), success) +mstore(0x5ec0, mload(0x8c0)) + mstore(0x5ee0, mload(0x8e0)) +mstore(0x5f00, mload(0x5040)) +success := and(eq(staticcall(gas(), 0x7, 0x5ec0, 0x60, 0x5ec0, 0x40), 1), success) +mstore(0x5f20, mload(0x5e40)) + mstore(0x5f40, mload(0x5e60)) +mstore(0x5f60, mload(0x5ec0)) + mstore(0x5f80, mload(0x5ee0)) +success := and(eq(staticcall(gas(), 0x6, 0x5f20, 0x80, 0x5f20, 0x40), 1), success) +mstore(0x5fa0, mload(0xde0)) + mstore(0x5fc0, mload(0xe00)) +mstore(0x5fe0, sub(f_q, mload(0x5080))) +success := and(eq(staticcall(gas(), 0x7, 0x5fa0, 0x60, 0x5fa0, 0x40), 1), success) +mstore(0x6000, mload(0x5f20)) + mstore(0x6020, mload(0x5f40)) +mstore(0x6040, mload(0x5fa0)) + mstore(0x6060, mload(0x5fc0)) +success := and(eq(staticcall(gas(), 0x6, 0x6000, 0x80, 0x6000, 0x40), 1), success) +mstore(0x6080, mload(0xe80)) + mstore(0x60a0, mload(0xea0)) +mstore(0x60c0, mload(0x50a0)) +success := and(eq(staticcall(gas(), 0x7, 0x6080, 0x60, 0x6080, 0x40), 1), success) +mstore(0x60e0, mload(0x6000)) + mstore(0x6100, mload(0x6020)) +mstore(0x6120, mload(0x6080)) + mstore(0x6140, mload(0x60a0)) +success := and(eq(staticcall(gas(), 0x6, 0x60e0, 0x80, 0x60e0, 0x40), 1), success) +mstore(0x6160, mload(0x60e0)) + mstore(0x6180, mload(0x6100)) +mstore(0x61a0, mload(0xe80)) + mstore(0x61c0, mload(0xea0)) +mstore(0x61e0, mload(0xec0)) + mstore(0x6200, mload(0xee0)) +mstore(0x6220, mload(0xf00)) + mstore(0x6240, mload(0xf20)) +mstore(0x6260, keccak256(0x6160, 256)) +mstore(25216, mod(mload(25184), f_q)) +mstore(0x62a0, mulmod(mload(0x6280), mload(0x6280), f_q)) +mstore(0x62c0, mulmod(1, mload(0x6280), f_q)) +mstore(0x62e0, mload(0x61e0)) + mstore(0x6300, mload(0x6200)) +mstore(0x6320, mload(0x62c0)) +success := and(eq(staticcall(gas(), 0x7, 0x62e0, 0x60, 0x62e0, 0x40), 1), success) +mstore(0x6340, mload(0x6160)) + mstore(0x6360, mload(0x6180)) +mstore(0x6380, mload(0x62e0)) + mstore(0x63a0, mload(0x6300)) +success := and(eq(staticcall(gas(), 0x6, 0x6340, 0x80, 0x6340, 0x40), 1), success) +mstore(0x63c0, mload(0x6220)) + mstore(0x63e0, mload(0x6240)) +mstore(0x6400, mload(0x62c0)) +success := and(eq(staticcall(gas(), 0x7, 0x63c0, 0x60, 0x63c0, 0x40), 1), success) +mstore(0x6420, mload(0x61a0)) + mstore(0x6440, mload(0x61c0)) +mstore(0x6460, mload(0x63c0)) + mstore(0x6480, mload(0x63e0)) +success := and(eq(staticcall(gas(), 0x6, 0x6420, 0x80, 0x6420, 0x40), 1), success) +mstore(0x64a0, mload(0x6340)) + mstore(0x64c0, mload(0x6360)) +mstore(0x64e0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0x6500, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x6520, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0x6540, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) +mstore(0x6560, mload(0x6420)) + mstore(0x6580, mload(0x6440)) +mstore(0x65a0, 0x172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b) + mstore(0x65c0, 0x2ae0c8c3a090f7200ff398ee9845bbae8f8c1445ae7b632212775f60a0e21600) + mstore(0x65e0, 0x190fa476a5b352809ed41d7a0d7fe12b8f685e3c12a6d83855dba27aaf469643) + mstore(0x6600, 0x1c0a500618907df9e4273d5181e31088deb1f05132de037cbfe73888f97f77c9) +success := and(eq(staticcall(gas(), 0x8, 0x64a0, 0x180, 0x64a0, 0x20), 1), success) +success := and(eq(mload(0x64a0), 1), success) + + // Revert if anything fails + if iszero(success) { revert(0, 0) } + + // Return empty bytes on success + return(0, 0) + + } + } +} + \ No newline at end of file diff --git a/releases/dev/verifier/interfaces/IOpenVmHalo2Verifier.sol b/releases/dev/verifier/interfaces/IOpenVmHalo2Verifier.sol new file mode 100644 index 00000000..ac8292cd --- /dev/null +++ b/releases/dev/verifier/interfaces/IOpenVmHalo2Verifier.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IOpenVmHalo2Verifier { + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + external + view; +} From 8e803f8bca67b9c05a9b73149c9b8faa708a7e25 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sun, 24 May 2026 09:33:27 +0800 Subject: [PATCH 12/19] fix perf --- crates/build-guest/src/main.rs | 4 ++-- crates/prover/src/prover/mod.rs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 11b78513..9740bcc3 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -357,8 +357,8 @@ fn generate_root_verifier(_workspace_dir: &Path, _force_overwrite: bool) -> Resu /// /// Must stay in sync with [`Prover::get_sdk`](crates/prover/src/prover/mod.rs). const DEFAULT_AGG_TREE_CONFIG: AggregationTreeConfig = AggregationTreeConfig { - num_children_internal: 2, - num_children_leaf: 2, + num_children_internal: 3, + num_children_leaf: 4, }; /// Generate the EVM verifier Solidity contract and its deployment bytecode. diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index c5244594..f95ede6d 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -50,8 +50,8 @@ fn default_agg_params() -> AggregationSystemParams { /// /// Must stay in sync with [`generate_evm_verifier`](crates/build-guest/src/main.rs). const DEFAULT_AGG_TREE_CONFIG: AggregationTreeConfig = AggregationTreeConfig { - num_children_internal: 2, - num_children_leaf: 2, + num_children_internal: 3, + num_children_leaf: 4, }; use crate::setup::read_app_exe; @@ -100,7 +100,6 @@ impl Prover { let segment_len = config.segment_len.unwrap_or(DEFAULT_SEGMENT_SIZE); let segmentation_limits = &mut app_config.app_vm_config.system.config.segmentation_config.limits; segmentation_limits.max_trace_height = segment_len as u32; - segmentation_limits.max_memory = 1_200_000_000_usize; // For 24G vram let app_exe = read_app_exe(&config.path_app_exe)?; Ok(Self { From 0eb9d55b3e3948c14ea2d002d85a74e15384f05c Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 28 May 2026 10:28:06 +0800 Subject: [PATCH 13/19] update --- AGENTS.md | 21 ++ Cargo.lock | 206 +++++++++++------- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- 8 files changed, 159 insertions(+), 80 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2577aff4..4a3a02cd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,6 +21,22 @@ This project uses **OpenVM v2.0.0-beta.2** as its ZKVM. Guest executables (`.vme - Field algebra APIs - ECC constructor signatures +### How to update OpenVM dependencies correctly + +OpenVM is declared as a **git dependency** (`branch = "develop-v2.1.0-rvr"`) in `Cargo.toml`, but the exact commit is pinned in `Cargo.lock`. Running a bare `cargo update` will **not** move the git branch forward; instead it will only bump unrelated crates.io packages (e.g. `alloy`, `revm`) which often break compatibility with the `scroll-tech/reth` and `sbv` forks. + +**Do NOT run a global `cargo update` unless you are prepared to upgrade the entire `alloy`/`revm`/`reth`/`sbv` dependency chain together.** + +To check whether the branch actually has new commits: +```bash +git ls-remote https://github.com/openvm-org/openvm.git develop-v2.1.0-rvr +``` +If the returned SHA differs from the one recorded in `Cargo.lock`, update only the OpenVM packages: +```bash +cargo update -p openvm +``` +Then rebuild guests and run tests as described below. + ### After ANY OpenVM version upgrade, you MUST: 1. **Update the hardcoded version string** in `crates/build-guest/src/verifier.rs`: @@ -85,6 +101,11 @@ This happens when: RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest -- --mode force ``` +### `cargo update` breaks compilation with alloy/revm type mismatches +**Symptoms**: Errors like `missing verify_and_compute_signer_unchecked in implementation` (alloy) or `mismatched types` between `revm_primitives::hardfork::SpecId` and `SpecId` (revm). +**Cause**: A global `cargo update` bumps `alloy` to 1.8.x and `revm` to 30.2.0, but the `scroll-tech/reth` and `sbv` forks were built against older versions. The `[patch.crates-io]` table pins `revm` to `scroll-v91` (30.1.1), which no longer satisfies the newer `alloy-evm` requirements, leading to duplicate registry versions of `revm-handler` / `revm-primitives` in the dependency graph. +**Fix**: Restore the original `Cargo.lock` (`git checkout HEAD -- Cargo.lock`) and update only what you actually need (e.g. `cargo update -p openvm`). + ### Docker build fails with stale CID The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. Use local build (`cargo run -p scroll-zkvm-build-guest`) as fallback. diff --git a/Cargo.lock b/Cargo.lock index b430518a..6bd68f83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "core_extensions", "crossbeam-channel", "generational-arena", - "libloading", + "libloading 0.7.4", "lock_api", "parking_lot", "paste", @@ -800,7 +800,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -811,7 +811,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2400,7 +2400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3506,7 +3506,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "ecdsa", "elliptic-curve", @@ -3566,6 +3566,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + [[package]] name = "libm" version = "0.2.15" @@ -3885,7 +3895,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4231,7 +4241,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4246,7 +4256,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "blstrs", "cfg-if", @@ -4281,7 +4291,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-macros-common", "quote", @@ -4291,7 +4301,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", @@ -4307,7 +4317,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "num-bigint", "num-prime", @@ -4319,7 +4329,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-algebra-guest", "openvm-instructions", @@ -4333,7 +4343,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "num-bigint", "num-traits", @@ -4343,7 +4353,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "clap", "eyre", @@ -4366,7 +4376,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4380,7 +4390,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4407,7 +4417,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4416,7 +4426,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-bigint-guest", "openvm-instructions", @@ -4431,7 +4441,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4443,7 +4453,7 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "abi_stable", "backtrace", @@ -4475,6 +4485,7 @@ dependencies = [ "p3-field", "rand 0.9.4", "rustc-hash 2.1.1", + "rvr-openvm", "serde", "serde-big-array", "static_assertions", @@ -4485,7 +4496,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4496,7 +4507,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4516,7 +4527,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4527,7 +4538,7 @@ dependencies = [ [[package]] name = "openvm-codec-derive" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4538,7 +4549,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4567,7 +4578,7 @@ dependencies = [ [[package]] name = "openvm-cpu-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "cfg-if", "derive-new 0.7.0", @@ -4592,7 +4603,7 @@ dependencies = [ [[package]] name = "openvm-cuda-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "derive-new 0.7.0", "getset", @@ -4619,7 +4630,7 @@ dependencies = [ [[package]] name = "openvm-cuda-builder" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "cc", "glob", @@ -4628,7 +4639,7 @@ dependencies = [ [[package]] name = "openvm-cuda-common" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "bytesize", "ctor", @@ -4642,7 +4653,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "proc-macro2", "quote", @@ -4652,7 +4663,7 @@ dependencies = [ [[package]] name = "openvm-deferral-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "dashmap", @@ -4686,7 +4697,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4695,7 +4706,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4711,7 +4722,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "blstrs", "cfg-if", @@ -4745,7 +4756,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "ecdsa", "elliptic-curve", @@ -4764,7 +4775,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-macros-common", "quote", @@ -4774,7 +4785,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-ecc-guest", "openvm-instructions", @@ -4788,7 +4799,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4805,7 +4816,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "quote", "syn 2.0.110", @@ -4814,7 +4825,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4823,7 +4834,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4851,7 +4862,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-platform", ] @@ -4859,7 +4870,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -4873,7 +4884,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "syn 2.0.110", ] @@ -4881,7 +4892,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4899,7 +4910,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4923,7 +4934,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4955,7 +4966,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4976,7 +4987,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-instructions", "openvm-pairing-guest", @@ -4989,7 +5000,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "libm", "openvm-custom-insn", @@ -4999,7 +5010,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "derivative", "lazy_static", @@ -5017,7 +5028,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "derive-new 0.6.0", "eyre", @@ -5046,7 +5057,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "quote", "syn 2.0.110", @@ -5055,7 +5066,7 @@ dependencies = [ [[package]] name = "openvm-rv32-adapters" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5072,7 +5083,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5100,7 +5111,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-custom-insn", "p3-field", @@ -5110,7 +5121,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5126,7 +5137,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "alloy-sol-types", "bitcode", @@ -5168,7 +5179,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "bon", "cfg-if", @@ -5203,7 +5214,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm", "openvm-sha2-guest", @@ -5213,7 +5224,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "ndarray", "num_enum", @@ -5227,7 +5238,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5256,7 +5267,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-platform", ] @@ -5264,7 +5275,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5278,7 +5289,7 @@ dependencies = [ [[package]] name = "openvm-stark-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "cfg-if", "derivative", @@ -5311,7 +5322,7 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#4cbc6b23dc9569be78ad8fa0c1188a4f88adfa4a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" dependencies = [ "dashmap", "derive-new 0.7.0", @@ -5342,7 +5353,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5366,7 +5377,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "elf", "eyre", @@ -5381,7 +5392,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5411,7 +5422,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "openvm-deferral-guest", ] @@ -5419,7 +5430,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "bitcode", "eyre", @@ -5458,7 +5469,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#b7b23b65d42b6028d7f1987da95f5d300be9dc36" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" dependencies = [ "ecdsa", "elliptic-curve", @@ -7804,7 +7815,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7834,6 +7845,53 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rvr-openvm" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +dependencies = [ + "openvm-instructions", + "openvm-platform", + "openvm-stark-backend", + "rvr-openvm-build", + "rvr-openvm-ext-ffi-common", + "rvr-openvm-ir", + "rvr-openvm-lift", + "thiserror 1.0.69", +] + +[[package]] +name = "rvr-openvm-build" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" + +[[package]] +name = "rvr-openvm-ext-ffi-common" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" + +[[package]] +name = "rvr-openvm-ir" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +dependencies = [ + "serde", +] + +[[package]] +name = "rvr-openvm-lift" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +dependencies = [ + "libloading 0.8.9", + "openvm-instructions", + "openvm-rv32im-transpiler", + "openvm-stark-backend", + "rvr-openvm-ext-ffi-common", + "rvr-openvm-ir", + "thiserror 1.0.69", +] + [[package]] name = "ryu" version = "1.0.20" @@ -8989,7 +9047,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index cd9d8ccf..e349621e 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [520116242, 438206942, 1460585682, 1080375955, 655525982, 291819449, 289597192, 739536847]; +pub const COMMIT: [u32; 8] = [766317859, 1466100623, 448395199, 974367704, 302748071, 704694885, 1339198858, 1801815569]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 3d972af1..41733dfa 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1585746298, 1227330313, 377026605, 1453044393, 1602011240, 557491268, 632299533, 1648695606]; +pub const COMMIT: [u32; 8] = [772371964, 1145789036, 930362816, 121650785, 1964150030, 22185745, 315619958, 1944508804]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index edefc4f4..1d4559c0 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1136275893, 1407154518, 920919977, 364816368, 1499414199, 1138007052, 1783034630, 977110994]; +pub const COMMIT: [u32; 8] = [581875746, 442957840, 1339819471, 1920189492, 1353682603, 888787100, 262934594, 240840491]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 3bb595a6..380056de 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1268707915, 137202277, 1407567349, 1777716679, 18254191, 1760215902, 572689567, 1219299492]; +pub const COMMIT: [u32; 8] = [974347609, 114156776, 457923839, 1050553778, 432147963, 1050658864, 1603044318, 992941814]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 7da902af..357592ac 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1735893845, 1221356996, 1546836896, 1762308944, 160310189, 2004482779, 1193790493, 1139072554]; +pub const COMMIT: [u32; 8] = [187125156, 63350109, 1371653157, 546156847, 795435931, 1333232655, 789017763, 787940235]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index 7a23999e..3485589f 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1367261305, 1725314385, 56774325, 974516987, 645567438, 1297433976, 1574497560, 1739847365]; +pub const COMMIT: [u32; 8] = [202359731, 208583537, 662858653, 1415275195, 1996877770, 296571987, 1956027988, 246689104]; From f7c52416608aeb99f407e1448ce10d27f6e5eca8 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sat, 6 Jun 2026 11:49:31 +0800 Subject: [PATCH 14/19] chore: upgrade openvm to 2d21d630 - cargo update -p openvm - rebuild guest assets (chunk/batch/bundle commitments + verifier) - test-single-chunk and test-e2e-bundle pass --- Cargo.lock | 135 +++++++++--------- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- releases/dev/verifier/Halo2Verifier.sol | 14 +- releases/dev/verifier/verifier.bin | Bin 19405 -> 19405 bytes 9 files changed, 83 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bd68f83..2365bde3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3506,7 +3506,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "ecdsa", "elliptic-curve", @@ -4241,7 +4241,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4256,7 +4256,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "blstrs", "cfg-if", @@ -4291,7 +4291,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-macros-common", "quote", @@ -4301,7 +4301,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", @@ -4317,7 +4317,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "num-bigint", "num-prime", @@ -4329,7 +4329,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-algebra-guest", "openvm-instructions", @@ -4343,7 +4343,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "num-bigint", "num-traits", @@ -4353,7 +4353,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "clap", "eyre", @@ -4376,7 +4376,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4390,7 +4390,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4417,7 +4417,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4426,7 +4426,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-bigint-guest", "openvm-instructions", @@ -4441,7 +4441,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4453,7 +4453,7 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "abi_stable", "backtrace", @@ -4496,7 +4496,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4507,7 +4507,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4527,7 +4527,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4549,7 +4549,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4653,7 +4653,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "proc-macro2", "quote", @@ -4663,7 +4663,7 @@ dependencies = [ [[package]] name = "openvm-deferral-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "dashmap", @@ -4697,7 +4697,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4706,7 +4706,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4722,7 +4722,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "blstrs", "cfg-if", @@ -4756,7 +4756,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "ecdsa", "elliptic-curve", @@ -4775,7 +4775,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-macros-common", "quote", @@ -4785,7 +4785,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-ecc-guest", "openvm-instructions", @@ -4799,7 +4799,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4816,7 +4816,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "quote", "syn 2.0.110", @@ -4825,7 +4825,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4834,7 +4834,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4862,7 +4862,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-platform", ] @@ -4870,7 +4870,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -4884,7 +4884,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "syn 2.0.110", ] @@ -4892,7 +4892,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4910,7 +4910,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4934,7 +4934,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4966,7 +4966,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4987,7 +4987,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-instructions", "openvm-pairing-guest", @@ -5000,7 +5000,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "libm", "openvm-custom-insn", @@ -5010,7 +5010,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "derivative", "lazy_static", @@ -5028,7 +5028,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "derive-new 0.6.0", "eyre", @@ -5057,7 +5057,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "quote", "syn 2.0.110", @@ -5066,7 +5066,7 @@ dependencies = [ [[package]] name = "openvm-rv32-adapters" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5083,7 +5083,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5111,7 +5111,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-custom-insn", "p3-field", @@ -5121,7 +5121,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5137,7 +5137,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "alloy-sol-types", "bitcode", @@ -5179,7 +5179,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "bon", "cfg-if", @@ -5214,7 +5214,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm", "openvm-sha2-guest", @@ -5224,7 +5224,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "ndarray", "num_enum", @@ -5238,7 +5238,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5267,7 +5267,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-platform", ] @@ -5275,7 +5275,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5353,7 +5353,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5377,7 +5377,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "elf", "eyre", @@ -5392,7 +5392,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5422,7 +5422,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-deferral-guest", ] @@ -5430,7 +5430,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "bitcode", "eyre", @@ -5469,7 +5469,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "ecdsa", "elliptic-curve", @@ -7848,10 +7848,11 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "openvm-instructions", "openvm-platform", + "openvm-rv32im-guest", "openvm-stark-backend", "rvr-openvm-build", "rvr-openvm-ext-ffi-common", @@ -7863,17 +7864,21 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" [[package]] name = "rvr-openvm-ext-ffi-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +dependencies = [ + "openvm-instructions", + "openvm-platform", +] [[package]] name = "rvr-openvm-ir" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "serde", ] @@ -7881,7 +7886,7 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#9ede114de0b5acfe760fc635ed68c032db0b33f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" dependencies = [ "libloading 0.8.9", "openvm-instructions", diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index e349621e..4de73611 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [766317859, 1466100623, 448395199, 974367704, 302748071, 704694885, 1339198858, 1801815569]; +pub const COMMIT: [u32; 8] = [50420542, 1392989157, 448926711, 1020586158, 1753185748, 978552653, 1987597656, 1535570790]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 41733dfa..90402c8d 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [772371964, 1145789036, 930362816, 121650785, 1964150030, 22185745, 315619958, 1944508804]; +pub const COMMIT: [u32; 8] = [786832452, 1653477522, 1394183768, 510849076, 34752204, 963795907, 1822012470, 1297862894]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 1d4559c0..1c18528d 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [581875746, 442957840, 1339819471, 1920189492, 1353682603, 888787100, 262934594, 240840491]; +pub const COMMIT: [u32; 8] = [2001906000, 1504752506, 1175753514, 1631401950, 1839606225, 783683098, 1568962809, 1700031006]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 380056de..fd07c014 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [974347609, 114156776, 457923839, 1050553778, 432147963, 1050658864, 1603044318, 992941814]; +pub const COMMIT: [u32; 8] = [96506945, 1189901216, 890045270, 1752802540, 1058621785, 813050117, 204020090, 49333955]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 357592ac..48c79073 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [187125156, 63350109, 1371653157, 546156847, 795435931, 1333232655, 789017763, 787940235]; +pub const COMMIT: [u32; 8] = [1531285366, 538142123, 1569134888, 1545025877, 1752434853, 561247774, 1106370680, 686967467]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index 3485589f..cfa3b260 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [202359731, 208583537, 662858653, 1415275195, 1996877770, 296571987, 1956027988, 246689104]; +pub const COMMIT: [u32; 8] = [1452956221, 435253581, 1946192292, 1141638848, 1783296127, 34745095, 1581934565, 1871321183]; diff --git a/releases/dev/verifier/Halo2Verifier.sol b/releases/dev/verifier/Halo2Verifier.sol index 1d410329..a9800f7f 100644 --- a/releases/dev/verifier/Halo2Verifier.sol +++ b/releases/dev/verifier/Halo2Verifier.sol @@ -76,7 +76,7 @@ mstore(0x5e0, mod(calldataload(0x540), f_q)) mstore(0x600, mod(calldataload(0x560), f_q)) mstore(0x620, mod(calldataload(0x580), f_q)) mstore(0x640, mod(calldataload(0x5a0), f_q)) -mstore(0x80, 18985003345801801897523588179503765829384406181366733198263515866464217011193) +mstore(0x80, 11470383548896865094596963285747371760877142442046712558647644420409192746327) { let x := calldataload(0x5c0) @@ -1419,8 +1419,8 @@ mstore(0x54a0, mload(0x53c0)) mstore(0x54e0, mload(0x5440)) mstore(0x5500, mload(0x5460)) success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) -mstore(0x5520, 0x2dc3c1b9bc2ea2927a6676f638518e06a6710821938d21f21f826a74e2df8e08) - mstore(0x5540, 0x1f3430811fcc367d5f54d03de701b5daa7a3d8c14e715cb57eabbcb949261d5f) +mstore(0x5520, 0x0fe832b93957c31992e2d46ed2165dd2d8ab3c9bf076c7254ff56b41632c4969) + mstore(0x5540, 0x284aacc69fa0f1c51cd331318a7ab78eec74104b87a569424bdd8b3385ebeefd) mstore(0x5560, mload(0x4ee0)) success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) mstore(0x5580, mload(0x54a0)) @@ -1455,8 +1455,8 @@ mstore(0x5820, mload(0x5740)) mstore(0x5860, mload(0x57c0)) mstore(0x5880, mload(0x57e0)) success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) -mstore(0x58a0, 0x2025edbb2ccedbde503fb0e916f46a4612168a34387d3779638be4d3f0e583fe) - mstore(0x58c0, 0x28d7541be8b364bd7b9dc7a3c8d8a96c4d13b3344b2c30e1f1634ece387e994e) +mstore(0x58a0, 0x289a66a38979069bea5696aa76d9c408823208e16c9bfe06e8e8c7ab65ced34b) + mstore(0x58c0, 0x1d310a2ef998c261d05b10a38c18919f46256afc5e8e1063691b22593b481c57) mstore(0x58e0, mload(0x4f60)) success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) mstore(0x5900, mload(0x5820)) @@ -1464,8 +1464,8 @@ mstore(0x5900, mload(0x5820)) mstore(0x5940, mload(0x58a0)) mstore(0x5960, mload(0x58c0)) success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) -mstore(0x5980, 0x11b54f0976d5fc08ec4deed8f5267cbb13f7dd56ee02902e258db064ec2a4d2e) - mstore(0x59a0, 0x2d1cd6dc1209909ec8aae309b36cc453c02e85940cf663a98ba51c5f768cf804) +mstore(0x5980, 0x0bc030890773e34d809fa0c09885fd47fd08053d40477964bd47914ea4fa9ca8) + mstore(0x59a0, 0x1bc6c4e5b649a5ff35b436ce387efefdb280c9f0702bfd96e08ffde45381d339) mstore(0x59c0, mload(0x4f80)) success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) mstore(0x59e0, mload(0x5900)) diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin index b1b80e88bb41dfb38749062ea5ebf61a4708c5c2..2a92b4ba6d42ad096d505b36778d68bfd60b3d82 100644 GIT binary patch delta 315 zcmV-B0mS~zmjTU}0k9tfAQ@Z%%o=7LU45KgV~`Gr7ZRCO?M{4Y^tT8-@$PO7SF=9@ z>pDdb=rXxESHl^S;?!=^7G2WVt2~?VcE=@8^=m<6EJ>~s)IhoxykOWlhzh3oG9vu{2t0!1jAW}}ID2Ak?uma2By#0Y{i2;pp-{s!pi z$E#(|(@SAkpi+MwF$ymEn8IPuTM(m+7?GbwC2IU$ju2yM8zNadNE}y_-#}MI3&1dm z2Xo_1fS;hin1%gE{Rjm;Ku39Gy+@Hwr23qwVOfAue;dZc<+e$s|24EW&NzPl{jz|` z@Ng^rmf(;58LjVX905h~?lWhP1 delta 315 zcmV-B0mS~zmjTU}0k9tfASwAFkI#vgg?Qh-u@#KCOVO}9k|gjxCm&qz;QOr;`LjO* z>pDd(!@;?{E~1ipW_I>CQH}NhTd%vu{2t0!1Jt?Yk__+ul$=u;~``YDN+kiZnQVH+f@= z`m_2^(K6~6ZhR#?gEf5C5^CT>?%zzVOfAue=Qu=+!6_pp2(`>3A1d(Q@}2T zlnnM`sf(o?Uv`Z61hacVCkiW8GT%SJBZK6nu87Jk;k7Ao+xG9lgz8lLwz< Nb8l>8LjVX905folm3{yK From 899d8350eea65d70f0843f8ab1c75340fe77a2c6 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 18 Jun 2026 16:48:54 +0800 Subject: [PATCH 15/19] chore: upgrade openvm to 64bfcb2a and simplify execute_guest - cargo update -p openvm (now at 64bfcb2a; stark-backend at 27bb74b9) - adapt to renamed SystemConfig::segmentation_limits - simplify execute_guest using Sdk::compile_metered_cost / execute_compiled_metered_cost and Sdk::execute, now safe because upstream fixed inventory lifetime in compiled instances - cargo check passes --- Cargo.lock | 188 ++++++++++++++------------------ crates/integration/src/lib.rs | 9 +- crates/prover/src/prover/mod.rs | 11 +- crates/prover/src/utils/vm.rs | 41 ++----- 4 files changed, 93 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2365bde3..d75ce7b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -800,7 +800,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -811,7 +811,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2364,18 +2364,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "enum_dispatch" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" -dependencies = [ - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.110", -] - [[package]] name = "enumn" version = "0.1.14" @@ -2400,7 +2388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -3506,7 +3494,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "ecdsa", "elliptic-curve", @@ -3895,7 +3883,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4241,7 +4229,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4256,7 +4244,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "blstrs", "cfg-if", @@ -4291,7 +4279,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-macros-common", "quote", @@ -4301,7 +4289,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", @@ -4317,7 +4305,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "num-bigint", "num-prime", @@ -4329,7 +4317,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-algebra-guest", "openvm-instructions", @@ -4343,7 +4331,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "num-bigint", "num-traits", @@ -4353,7 +4341,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "clap", "eyre", @@ -4376,7 +4364,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4390,7 +4378,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4417,7 +4405,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4426,7 +4414,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-bigint-guest", "openvm-instructions", @@ -4441,7 +4429,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4453,17 +4441,15 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "abi_stable", "backtrace", "bytesize", "cfg-if", "dashmap", - "derivative", "derive-new 0.6.0", "derive_more 1.0.0", - "enum_dispatch", "eyre", "getset", "itertools 0.14.0", @@ -4496,7 +4482,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4507,7 +4493,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4527,7 +4513,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4538,7 +4524,7 @@ dependencies = [ [[package]] name = "openvm-codec-derive" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4549,7 +4535,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4560,7 +4546,6 @@ dependencies = [ "openvm-circuit-primitives", "openvm-cpu-backend", "openvm-cuda-backend", - "openvm-cuda-builder", "openvm-cuda-common", "openvm-poseidon2-air", "openvm-recursion-circuit", @@ -4578,7 +4563,7 @@ dependencies = [ [[package]] name = "openvm-cpu-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "cfg-if", "derive-new 0.7.0", @@ -4603,7 +4588,7 @@ dependencies = [ [[package]] name = "openvm-cuda-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "derive-new 0.7.0", "getset", @@ -4630,7 +4615,7 @@ dependencies = [ [[package]] name = "openvm-cuda-builder" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "cc", "glob", @@ -4639,7 +4624,7 @@ dependencies = [ [[package]] name = "openvm-cuda-common" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "bytesize", "ctor", @@ -4653,7 +4638,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "proc-macro2", "quote", @@ -4663,13 +4648,12 @@ dependencies = [ [[package]] name = "openvm-deferral-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "dashmap", "derive-new 0.6.0", "derive_more 1.0.0", - "eyre", "itertools 0.14.0", "openvm-circuit", "openvm-circuit-derive", @@ -4683,21 +4667,18 @@ dependencies = [ "openvm-instructions", "openvm-poseidon2-air", "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "p3-field", "rand 0.9.4", "rustc-hash 2.1.1", "serde", - "static_assertions", - "strum 0.26.3", ] [[package]] name = "openvm-deferral-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4706,7 +4687,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4722,7 +4703,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "blstrs", "cfg-if", @@ -4756,7 +4737,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "ecdsa", "elliptic-curve", @@ -4775,7 +4756,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-macros-common", "quote", @@ -4785,7 +4766,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-ecc-guest", "openvm-instructions", @@ -4799,7 +4780,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4816,7 +4797,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "quote", "syn 2.0.110", @@ -4825,7 +4806,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4834,7 +4815,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4862,7 +4843,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-platform", ] @@ -4870,7 +4851,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -4884,7 +4865,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "syn 2.0.110", ] @@ -4892,7 +4873,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4910,7 +4891,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4934,7 +4915,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4966,7 +4947,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4987,7 +4968,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-instructions", "openvm-pairing-guest", @@ -5000,7 +4981,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "libm", "openvm-custom-insn", @@ -5010,7 +4991,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "derivative", "lazy_static", @@ -5028,10 +5009,9 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "derive-new 0.6.0", - "eyre", "itertools 0.14.0", "openvm-circuit", "openvm-circuit-primitives", @@ -5057,7 +5037,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "quote", "syn 2.0.110", @@ -5066,7 +5046,7 @@ dependencies = [ [[package]] name = "openvm-rv32-adapters" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5083,7 +5063,7 @@ dependencies = [ [[package]] name = "openvm-rv32im-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5111,17 +5091,16 @@ dependencies = [ [[package]] name = "openvm-rv32im-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-custom-insn", - "p3-field", "strum_macros 0.26.4", ] [[package]] name = "openvm-rv32im-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5137,11 +5116,10 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "alloy-sol-types", "bitcode", - "bon", "cfg-if", "clap", "derivative", @@ -5152,7 +5130,6 @@ dependencies = [ "halo2-base", "hex", "itertools 0.14.0", - "num-bigint", "openvm", "openvm-build", "openvm-circuit", @@ -5165,26 +5142,24 @@ dependencies = [ "openvm-stark-sdk", "openvm-static-verifier", "openvm-transpiler", + "openvm-verify-stark-circuit", "openvm-verify-stark-host", - "p3-bn254", "serde", "serde_json", "serde_with", "tempfile", "thiserror 1.0.69", - "toml", "tracing", ] [[package]] name = "openvm-sdk-config" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "bon", "cfg-if", "derive_more 1.0.0", - "openvm", "openvm-algebra-circuit", "openvm-algebra-transpiler", "openvm-bigint-circuit", @@ -5214,9 +5189,8 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ - "openvm", "openvm-sha2-guest", "sha2 0.10.9", ] @@ -5224,7 +5198,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "ndarray", "num_enum", @@ -5238,7 +5212,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5267,7 +5241,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-platform", ] @@ -5275,7 +5249,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5289,7 +5263,7 @@ dependencies = [ [[package]] name = "openvm-stark-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "cfg-if", "derivative", @@ -5322,7 +5296,7 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#12c8f9eebf9622972244473d9058ca6f560033eb" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" dependencies = [ "dashmap", "derive-new 0.7.0", @@ -5353,14 +5327,13 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "halo2-base", "itertools 0.14.0", "num-bigint", "num-integer", "once_cell", - "openvm-circuit-primitives-derive", "openvm-continuations", "openvm-cpu-backend", "openvm-recursion-circuit", @@ -5377,7 +5350,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "elf", "eyre", @@ -5392,7 +5365,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5403,7 +5376,6 @@ dependencies = [ "openvm-continuations", "openvm-cpu-backend", "openvm-cuda-backend", - "openvm-cuda-builder", "openvm-cuda-common", "openvm-deferral-circuit", "openvm-poseidon2-air", @@ -5413,7 +5385,6 @@ dependencies = [ "openvm-stark-sdk", "openvm-verify-stark-host", "p3-air", - "p3-bn254", "p3-field", "p3-matrix", "tracing", @@ -5422,7 +5393,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-deferral-guest", ] @@ -5430,7 +5401,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "bitcode", "eyre", @@ -5469,7 +5440,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "ecdsa", "elliptic-curve", @@ -7815,7 +7786,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -7848,9 +7819,8 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ - "openvm-instructions", "openvm-platform", "openvm-rv32im-guest", "openvm-stark-backend", @@ -7864,12 +7834,12 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" [[package]] name = "rvr-openvm-ext-ffi-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "openvm-instructions", "openvm-platform", @@ -7878,7 +7848,7 @@ dependencies = [ [[package]] name = "rvr-openvm-ir" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "serde", ] @@ -7886,7 +7856,7 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#2d21d6303559c989dc3f71617a725476f1ef328d" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" dependencies = [ "libloading 0.8.9", "openvm-instructions", @@ -9052,7 +9022,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index feef379f..e92519e6 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -374,18 +374,13 @@ pub fn tester_execute( .map(|p| p.as_stark_proof().expect("must be stark proof")), )?; - let app_vm_config = app_config.app_vm_config.clone(); + let _app_vm_config = app_config.app_vm_config.clone(); let sdk = Sdk::builder() .app_config(app_config) .agg_pk(AGG_STARK_PROVING_KEY.clone()) .build() .map_err(|e| eyre::eyre!("sdk build failed: {e}"))?; - let ret = scroll_zkvm_prover::utils::vm::execute_guest( - &sdk, - app_vm_config.as_ref(), - app_exe, - &stdin, - )?; + let ret = scroll_zkvm_prover::utils::vm::execute_guest(&sdk, app_exe, &stdin)?; Ok(ret) } diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index f95ede6d..b69d3bf2 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -98,7 +98,7 @@ impl Prover { pub fn setup(config: ProverConfig, name: Option<&str>) -> Result { let mut app_config = read_app_config(&config.path_app_config)?; let segment_len = config.segment_len.unwrap_or(DEFAULT_SEGMENT_SIZE); - let segmentation_limits = &mut app_config.app_vm_config.system.config.segmentation_config.limits; + let segmentation_limits = &mut app_config.app_vm_config.system.config.segmentation_limits; segmentation_limits.max_trace_height = segment_len as u32; let app_exe = read_app_exe(&config.path_app_exe)?; @@ -271,13 +271,8 @@ impl Prover { ) -> Result { let sdk = self.get_sdk()?; let t = std::time::Instant::now(); - let exec_result = crate::utils::vm::execute_guest( - sdk, - self.app_config.app_vm_config.as_ref(), - self.app_exe.clone(), - stdin, - ) - .map_err(|e| Error::GenProof(e.to_string()))?; + let exec_result = crate::utils::vm::execute_guest(sdk, self.app_exe.clone(), stdin) + .map_err(|e| Error::GenProof(e.to_string()))?; let execution_time_mills = t.elapsed().as_millis() as u64; let execution_time_s = execution_time_mills as f32 / 1000.0f32; let exec_speed = (exec_result.total_cycle as f32 / 1_000_000.0f32) / execution_time_s; // MHz diff --git a/crates/prover/src/utils/vm.rs b/crates/prover/src/utils/vm.rs index 2a2486f2..a7babe03 100644 --- a/crates/prover/src/utils/vm.rs +++ b/crates/prover/src/utils/vm.rs @@ -1,7 +1,3 @@ -use openvm_circuit::{ - arch::{SystemConfig, VirtualMachineError}, - system::memory::merkle::public_values::extract_public_values, -}; use openvm_sdk::{Sdk, SdkError, StdIn, types::ExecutableFormat}; pub struct ExecutionResult { @@ -20,34 +16,21 @@ const COST_CYCLE_RATIO: u64 = 87u64; // on the size of the execution process. pub fn execute_guest( sdk: &Sdk, - sys_config: &SystemConfig, exe: impl Into, inputs: &StdIn, ) -> Result { - let app_prover = sdk.app_prover(exe)?; - - let vm = app_prover.vm(); - let exe = app_prover.exe(); - - let ctx = vm.build_metered_cost_ctx(); - let preset_max_cost = ctx.max_execution_cost * 2; + let exe = sdk.convert_to_exe(exe)?; + let mut compiled = sdk.compile_metered_cost(exe.clone())?; + let preset_max_cost = compiled.ctx.max_execution_cost * 2; let estimated_max_cycles = preset_max_cost / COST_CYCLE_RATIO; tracing::info!("Double preset max cost to ({preset_max_cost}) for metering execution"); - let ctx = ctx.with_max_execution_cost(preset_max_cost); - let interpreter = vm - .metered_cost_interpreter(&exe) - .map_err(VirtualMachineError::from)?; - - let (ctx, final_state) = interpreter - .execute_metered_cost(inputs.clone(), ctx) - .map_err(VirtualMachineError::from)?; - let mut total_cycle = ctx.instret; - - let mut public_values = - extract_public_values(sys_config.num_public_values, &final_state.memory.memory); + compiled.ctx = compiled.ctx.with_max_execution_cost(preset_max_cost); + let (mut public_values, (cost, instret)) = + sdk.execute_compiled_metered_cost(&compiled, inputs.clone())?; + let mut total_cycle = instret; if public_values.iter().all(|x| *x == 0) { - if ctx.cost < ctx.max_execution_cost { + if cost < compiled.ctx.max_execution_cost { return Err(SdkError::Other(eyre::eyre!( "public_values are all 0s for unexpected reason" ))); @@ -56,13 +39,7 @@ pub fn execute_guest( tracing::warn!( "Large execution exceed limit of metered execution, cycle is expected to >{estimated_max_cycles}" ); - let exe = sdk.convert_to_exe(exe)?; - let instance = vm.interpreter(&exe).map_err(VirtualMachineError::from)?; - let final_memory = instance - .execute(inputs.clone(), None) - .map_err(VirtualMachineError::from)? - .memory; - public_values = extract_public_values(sys_config.num_public_values, &final_memory.memory); + public_values = sdk.execute(exe, inputs.clone())?; total_cycle = estimated_max_cycles; if public_values.iter().all(|x| *x == 0) { From 5aea7a825101da1f2136ce1f48e00d02d47a56a5 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sun, 21 Jun 2026 19:17:17 +0800 Subject: [PATCH 16/19] chore: switch openvm to develop-v2.1.0-rv64 - update Cargo.toml branch and package mappings (rv32im -> riscv) - adapt to rv64 SDK API renames: execute_metered_cost, compile/execute split, riscv64 config - remove trace-height segmentation limit (RV64 uses memory-based segmentation) - simplify read_witnesses to openvm::io::read_vec - remove obsolete BenchmarkCli::profiling usage - cargo check passes --- Cargo.lock | 783 +++++++++++++----- Cargo.toml | 64 +- crates/build-guest/src/main.rs | 6 +- crates/integration/src/bin/chunk-benchmark.rs | 22 +- crates/prover/src/prover/mod.rs | 9 +- crates/prover/src/utils/vm.rs | 5 +- crates/types/circuit/src/io.rs | 28 +- crates/types/src/zkvm.rs | 2 +- 8 files changed, 637 insertions(+), 282 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d75ce7b6..af9c45e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ version = "0.9.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e713c57c2a2b19159e7be83b9194600d7e8eb3b7c2cd67e671adf47ce189a05" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cipher", "cpufeatures", ] @@ -106,7 +106,8 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -391,7 +392,7 @@ checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" dependencies = [ "alloy-rlp", "bytes", - "cfg-if", + "cfg-if 1.0.4", "const-hex", "derive_more 2.0.1", "foldhash 0.2.0", @@ -800,7 +801,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -811,7 +812,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1186,6 +1187,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "aurora-engine-modexp" version = "1.2.0" @@ -1226,7 +1238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 1.0.4", "libc", "miniz_oxide", "object 0.37.3", @@ -1323,6 +1335,12 @@ dependencies = [ "hex-conservative", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.10.0" @@ -1608,6 +1626,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.4" @@ -1716,7 +1740,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures", "proptest", "serde_core", @@ -1973,6 +1997,24 @@ dependencies = [ "cipher", ] +[[package]] +name = "cuda-config" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee74643f7430213a1a78320f88649de309b20b80818325575e393f848f79f5d" +dependencies = [ + "glob", +] + +[[package]] +name = "cuda-driver-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d4c552cc0de854877d80bcd1f11db75d42be32962d72a6799b88dcca88fffbd" +dependencies = [ + "cuda-config", +] + [[package]] name = "cudarc" version = "0.9.15" @@ -2056,7 +2098,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", @@ -2375,6 +2417,19 @@ dependencies = [ "syn 2.0.110", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -2388,7 +2443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2532,6 +2587,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2687,7 +2751,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -2707,7 +2771,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "wasi", ] @@ -2718,7 +2782,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "libc", "r-efi", @@ -2795,7 +2859,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "futures-sink", "futures-timer", "futures-util", @@ -2866,6 +2930,45 @@ dependencies = [ "tracing", ] +[[package]] +name = "halo2-axiom-gpu" +version = "1.0.0-rc.0" +source = "git+https://github.com/axiom-crypto/halo2-gpu.git?tag=v1.0.0-rc.0#fa3d662335d8f913660460d443509a84d1f3242f" +dependencies = [ + "ahash", + "anyhow", + "ark-std 0.3.0", + "blake2b_simd", + "cfg-if 0.1.10", + "colored", + "crossbeam", + "cuda-driver-sys", + "env_logger", + "ff 0.13.1", + "git-version", + "group 0.13.0", + "halo2curves-axiom 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.11.0", + "lazy_static", + "libc", + "log", + "num-bigint", + "num-integer", + "once_cell", + "openvm-cuda-builder", + "openvm-cuda-common", + "pairing 0.23.0", + "rand 0.8.6", + "rand_core 0.6.4", + "rayon", + "rustacuda", + "rustc-hash 1.1.0", + "sha3", + "subtle", + "tracing", + "yastl", +] + [[package]] name = "halo2-base" version = "0.5.0" @@ -2887,13 +2990,53 @@ dependencies = [ "serde_json", ] +[[package]] +name = "halo2-base" +version = "0.5.2" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.2#b4031ae0adb7cb37650ebd85c40631d8fca44237" +dependencies = [ + "getset", + "halo2-axiom", + "halo2-axiom-gpu", + "itertools 0.11.0", + "log", + "num-bigint", + "num-integer", + "num-traits", + "poseidon-primitives", + "rand_chacha 0.3.1", + "rayon", + "rustc-hash 1.1.0", + "serde", + "serde_json", +] + [[package]] name = "halo2-ecc" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c00681fdd1febaf552d8814e9f5a6a142d81a1514102190da07039588b366" dependencies = [ - "halo2-base", + "halo2-base 0.5.0", + "itertools 0.11.0", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.8.6", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "rayon", + "serde", + "serde_json", + "test-case", +] + +[[package]] +name = "halo2-ecc" +version = "0.5.2" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.2#b4031ae0adb7cb37650ebd85c40631d8fca44237" +dependencies = [ + "halo2-base 0.5.2", "itertools 0.11.0", "num-bigint", "num-integer", @@ -3024,6 +3167,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.5.2" @@ -3118,6 +3270,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "hybrid-array" version = "0.4.5" @@ -3482,7 +3643,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "ecdsa", "elliptic-curve", "once_cell", @@ -3494,7 +3655,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "ecdsa", "elliptic-curve", @@ -3550,7 +3711,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "winapi", ] @@ -3560,7 +3721,7 @@ version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "windows-link 0.2.1", ] @@ -3703,7 +3864,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "rayon", ] @@ -3883,7 +4044,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4001,7 +4162,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi", + "hermit-abi 0.5.2", "libc", ] @@ -4056,7 +4217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" dependencies = [ "alloy-rlp", - "cfg-if", + "cfg-if 1.0.4", "proptest", "ruint", "serde", @@ -4069,7 +4230,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags", + "bitflags 2.10.0", ] [[package]] @@ -4189,8 +4350,8 @@ version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ - "bitflags", - "cfg-if", + "bitflags 2.10.0", + "cfg-if 1.0.4", "foreign-types", "libc", "openssl-macros", @@ -4229,7 +4390,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4237,17 +4398,17 @@ dependencies = [ "num-bigint", "openvm-custom-insn", "openvm-platform", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde", ] [[package]] name = "openvm-algebra-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "blstrs", - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -4266,8 +4427,8 @@ dependencies = [ "openvm-cuda-common", "openvm-instructions", "openvm-mod-circuit-builder", - "openvm-rv32-adapters", - "openvm-rv32im-circuit", + "openvm-riscv-adapters", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4279,7 +4440,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-macros-common", "quote", @@ -4289,7 +4450,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", @@ -4297,7 +4458,7 @@ dependencies = [ "openvm-algebra-complex-macros", "openvm-algebra-moduli-macros", "openvm-custom-insn", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde-big-array", "strum_macros 0.26.4", ] @@ -4305,7 +4466,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "num-bigint", "num-prime", @@ -4317,21 +4478,21 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-algebra-guest", + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-algebra-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "num-bigint", "num-traits", @@ -4341,7 +4502,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "clap", "eyre", @@ -4364,7 +4525,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4378,9 +4539,9 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "openvm-bigint-transpiler", @@ -4393,9 +4554,9 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", - "openvm-rv32-adapters", - "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", + "openvm-riscv-adapters", + "openvm-riscv-circuit", + "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4405,7 +4566,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4414,22 +4575,22 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-bigint-guest", + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", - "openvm-rv32im-transpiler", + "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4441,12 +4602,12 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "abi_stable", "backtrace", "bytesize", - "cfg-if", + "cfg-if 1.0.4", "dashmap", "derive-new 0.6.0", "derive_more 1.0.0", @@ -4482,7 +4643,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4493,7 +4654,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4513,7 +4674,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4524,7 +4685,7 @@ dependencies = [ [[package]] name = "openvm-codec-derive" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4535,9 +4696,9 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "eyre", "itertools 0.14.0", @@ -4563,9 +4724,9 @@ dependencies = [ [[package]] name = "openvm-cpu-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.7.0", "getset", "itertools 0.14.0", @@ -4588,7 +4749,7 @@ dependencies = [ [[package]] name = "openvm-cuda-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ "derive-new 0.7.0", "getset", @@ -4615,7 +4776,7 @@ dependencies = [ [[package]] name = "openvm-cuda-builder" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ "cc", "glob", @@ -4624,7 +4785,7 @@ dependencies = [ [[package]] name = "openvm-cuda-common" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ "bytesize", "ctor", @@ -4638,19 +4799,24 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "proc-macro2", "quote", "syn 2.0.110", ] +[[package]] +name = "openvm-decoder" +version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" + [[package]] name = "openvm-deferral-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "dashmap", "derive-new 0.6.0", "derive_more 1.0.0", @@ -4666,7 +4832,7 @@ dependencies = [ "openvm-deferral-transpiler", "openvm-instructions", "openvm-poseidon2-air", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "p3-field", @@ -4678,7 +4844,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4687,7 +4853,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4703,10 +4869,10 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "blstrs", - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4725,7 +4891,8 @@ dependencies = [ "openvm-ecc-transpiler", "openvm-instructions", "openvm-mod-circuit-builder", - "openvm-rv32-adapters", + "openvm-riscv-adapters", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4737,7 +4904,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "ecdsa", "elliptic-curve", @@ -4748,7 +4915,7 @@ dependencies = [ "openvm-algebra-guest", "openvm-custom-insn", "openvm-ecc-sw-macros", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde", "strum_macros 0.26.4", ] @@ -4756,7 +4923,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-macros-common", "quote", @@ -4766,21 +4933,21 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ + "openvm-decoder", "openvm-ecc-guest", "openvm-instructions", "openvm-instructions-derive", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-instructions" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4797,7 +4964,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "quote", "syn 2.0.110", @@ -4806,7 +4973,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4815,7 +4982,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4830,7 +4997,7 @@ dependencies = [ "openvm-cuda-common", "openvm-instructions", "openvm-keccak256-transpiler", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "p3-keccak-air", @@ -4843,7 +5010,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-platform", ] @@ -4851,21 +5018,21 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-keccak256-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-macros-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "syn 2.0.110", ] @@ -4873,7 +5040,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4891,7 +5058,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4908,16 +5075,16 @@ dependencies = [ "openvm-ecc-sw-macros", "openvm-pairing-guest", "openvm-platform", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde", ] [[package]] name = "openvm-pairing-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -4936,7 +5103,7 @@ dependencies = [ "openvm-mod-circuit-builder", "openvm-pairing-guest", "openvm-pairing-transpiler", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4947,7 +5114,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -4968,30 +5135,30 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-pairing-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-platform" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "libm", "openvm-custom-insn", - "openvm-rv32im-guest", + "openvm-riscv-guest", ] [[package]] name = "openvm-poseidon2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "derivative", "lazy_static", @@ -5009,7 +5176,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5037,16 +5204,16 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "quote", "syn 2.0.110", ] [[package]] -name = "openvm-rv32-adapters" +name = "openvm-riscv-adapters" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5054,18 +5221,18 @@ dependencies = [ "openvm-circuit-primitives", "openvm-circuit-primitives-derive", "openvm-instructions", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", ] [[package]] -name = "openvm-rv32im-circuit" +name = "openvm-riscv-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -5080,34 +5247,35 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", - "openvm-rv32im-transpiler", + "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", "serde", "strum 0.26.3", + "tracing", ] [[package]] -name = "openvm-rv32im-guest" +name = "openvm-riscv-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", ] [[package]] -name = "openvm-rv32im-transpiler" +name = "openvm-riscv-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "serde", "strum 0.26.3", "tracing", @@ -5116,18 +5284,18 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "alloy-sol-types", "bitcode", - "cfg-if", + "cfg-if 1.0.4", "clap", "derivative", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", "getset", - "halo2-base", + "halo2-base 0.5.2", "hex", "itertools 0.14.0", "openvm", @@ -5155,10 +5323,10 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "bon", - "cfg-if", + "cfg-if 1.0.4", "derive_more 1.0.0", "openvm-algebra-circuit", "openvm-algebra-transpiler", @@ -5175,8 +5343,8 @@ dependencies = [ "openvm-keccak256-transpiler", "openvm-pairing-circuit", "openvm-pairing-transpiler", - "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", + "openvm-riscv-circuit", + "openvm-riscv-transpiler", "openvm-sha2-circuit", "openvm-sha2-transpiler", "openvm-stark-backend", @@ -5189,7 +5357,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5198,7 +5366,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "ndarray", "num_enum", @@ -5212,9 +5380,9 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "itertools 0.14.0", @@ -5228,7 +5396,7 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-sha2-air", "openvm-sha2-transpiler", "openvm-stark-backend", @@ -5241,7 +5409,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-platform", ] @@ -5249,23 +5417,23 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-sha2-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-stark-backend" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derivative", "derive-new 0.7.0", "eyre", @@ -5296,7 +5464,7 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" version = "2.0.0-alpha" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#27bb74b90bed66f738add281285b703dc47e129a" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ "dashmap", "derive-new 0.7.0", @@ -5327,15 +5495,16 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "halo2-base", + "halo2-base 0.5.2", "itertools 0.14.0", "num-bigint", "num-integer", "once_cell", "openvm-continuations", "openvm-cpu-backend", + "openvm-cuda-backend", "openvm-recursion-circuit", "openvm-stark-sdk", "openvm-verify-stark-host", @@ -5343,21 +5512,21 @@ dependencies = [ "serde", "serde_json", "serde_with", - "snark-verifier-sdk", + "snark-verifier-sdk 0.2.4", "tracing", ] [[package]] name = "openvm-transpiler" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "elf", "eyre", + "openvm-decoder", "openvm-instructions", "openvm-platform", "openvm-stark-backend", - "rrs-lib", "rustc-demangle", "thiserror 1.0.69", ] @@ -5365,9 +5534,9 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "eyre", "itertools 0.14.0", @@ -5393,7 +5562,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-deferral-guest", ] @@ -5401,7 +5570,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "bitcode", "eyre", @@ -5440,7 +5609,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "ecdsa", "elliptic-curve", @@ -5739,7 +5908,7 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "redox_syscall", "smallvec", @@ -5938,7 +6107,7 @@ version = "0.7.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffd40cc99d0fbb02b4b3771346b811df94194bc103983efa0203c8893755085" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures", "universal-hash", ] @@ -6097,7 +6266,7 @@ checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", - "bitflags", + "bitflags 2.10.0", "num-traits", "rand 0.9.4", "rand_chacha 0.9.0", @@ -6256,7 +6425,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags", + "bitflags 2.10.0", ] [[package]] @@ -6291,7 +6460,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.10.0", ] [[package]] @@ -6924,6 +7093,25 @@ dependencies = [ "revm-state 3.0.0", ] +[[package]] +name = "revm" +version = "27.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6bf82101a1ad8a2b637363a37aef27f88b4efc8a6e24c72bf5f64923dc5532" +dependencies = [ + "revm-bytecode 6.2.2", + "revm-context 8.0.4", + "revm-context-interface 9.0.0", + "revm-database 7.0.5", + "revm-database-interface 7.0.5", + "revm-handler 8.1.0", + "revm-inspector 8.1.0", + "revm-interpreter 24.0.0", + "revm-precompile 25.0.0", + "revm-primitives 20.2.1", + "revm-state 7.0.5", +] + [[package]] name = "revm" version = "29.0.1" @@ -7033,7 +7221,7 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9765628dfea4f3686aa8f2a72471c52801e6b38b601939ac16965f49bac66580" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-where", "revm-bytecode 3.0.0", "revm-context-interface 3.0.0", @@ -7043,6 +7231,22 @@ dependencies = [ "serde", ] +[[package]] +name = "revm-context" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd508416a35a4d8a9feaf5ccd06ac6d6661cd31ee2dc0252f9f7316455d71f9" +dependencies = [ + "cfg-if 1.0.4", + "derive-where", + "revm-bytecode 6.2.2", + "revm-context-interface 9.0.0", + "revm-database-interface 7.0.5", + "revm-primitives 20.2.1", + "revm-state 7.0.5", + "serde", +] + [[package]] name = "revm-context" version = "9.1.0" @@ -7050,7 +7254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a20c98e7008591a6f012550c2a00aa36cba8c14cc88eb88dec32eb9102554b4" dependencies = [ "bitvec", - "cfg-if", + "cfg-if 1.0.4", "derive-where", "revm-bytecode 6.2.2", "revm-context-interface 10.2.0", @@ -7066,7 +7270,7 @@ version = "10.1.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ "bitvec", - "cfg-if", + "cfg-if 1.0.4", "derive-where", "revm-bytecode 7.0.1", "revm-context-interface 11.1.1", @@ -7083,7 +7287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7adcce0c14cf59b7128de34185a0fbf8f63309539b9263b35ead870d73584114" dependencies = [ "bitvec", - "cfg-if", + "cfg-if 1.0.4", "derive-where", "revm-bytecode 7.1.1", "revm-context-interface 11.1.2", @@ -7108,6 +7312,22 @@ dependencies = [ "serde", ] +[[package]] +name = "revm-context-interface" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc90302642d21c8f93e0876e201f3c5f7913c4fcb66fb465b0fd7b707dfe1c79" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface 7.0.5", + "revm-primitives 20.2.1", + "revm-state 7.0.5", + "serde", +] + [[package]] name = "revm-context-interface" version = "10.2.0" @@ -7278,6 +7498,25 @@ dependencies = [ "serde", ] +[[package]] +name = "revm-handler" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1529c8050e663be64010e80ec92bf480315d21b1f2dbf65540028653a621b27d" +dependencies = [ + "auto_impl", + "derive-where", + "revm-bytecode 6.2.2", + "revm-context 8.0.4", + "revm-context-interface 9.0.0", + "revm-database-interface 7.0.5", + "revm-interpreter 24.0.0", + "revm-precompile 25.0.0", + "revm-primitives 20.2.1", + "revm-state 7.0.5", + "serde", +] + [[package]] name = "revm-handler" version = "10.0.1" @@ -7351,6 +7590,24 @@ dependencies = [ "serde_json", ] +[[package]] +name = "revm-inspector" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78db140e332489094ef314eaeb0bd1849d6d01172c113ab0eb6ea8ab9372926" +dependencies = [ + "auto_impl", + "either", + "revm-context 8.0.4", + "revm-database-interface 7.0.5", + "revm-handler 8.1.0", + "revm-interpreter 24.0.0", + "revm-primitives 20.2.1", + "revm-state 7.0.5", + "serde", + "serde_json", +] + [[package]] name = "revm-inspector" version = "10.0.1" @@ -7416,6 +7673,18 @@ dependencies = [ "serde", ] +[[package]] +name = "revm-interpreter" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff9d7d9d71e8a33740b277b602165b6e3d25fff091ba3d7b5a8d373bf55f28a7" +dependencies = [ + "revm-bytecode 6.2.2", + "revm-context-interface 9.0.0", + "revm-primitives 20.2.1", + "serde", +] + [[package]] name = "revm-interpreter" version = "25.0.3" @@ -7467,7 +7736,7 @@ dependencies = [ "aurora-engine-modexp", "blst", "c-kzg", - "cfg-if", + "cfg-if 1.0.4", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1", "once_cell", @@ -7478,6 +7747,33 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "revm-precompile" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cee3f336b83621294b4cfe84d817e3eef6f3d0fce00951973364cc7f860424d" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "arrayref", + "aurora-engine-modexp", + "blst", + "c-kzg", + "cfg-if 1.0.4", + "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1", + "once_cell", + "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "revm-primitives 20.2.1", + "ripemd", + "rug", + "secp256k1 0.31.1", + "sha2 0.10.9", +] + [[package]] name = "revm-precompile" version = "27.0.0" @@ -7493,7 +7789,7 @@ dependencies = [ "aurora-engine-modexp", "blst", "c-kzg", - "cfg-if", + "cfg-if 1.0.4", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -7517,7 +7813,7 @@ dependencies = [ "arrayref", "aurora-engine-modexp", "c-kzg", - "cfg-if", + "cfg-if 1.0.4", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", "revm-primitives 21.0.1", @@ -7593,7 +7889,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dd121f6e66d75ab111fb51b4712f129511569bc3e41e6067ae760861418bd8" dependencies = [ - "bitflags", + "bitflags 2.10.0", "revm-bytecode 3.0.0", "revm-primitives 18.0.0", "serde", @@ -7605,7 +7901,7 @@ version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" dependencies = [ - "bitflags", + "bitflags 2.10.0", "revm-bytecode 6.2.2", "revm-primitives 20.2.1", "serde", @@ -7616,7 +7912,7 @@ name = "revm-state" version = "8.0.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ - "bitflags", + "bitflags 2.10.0", "revm-bytecode 7.0.1", "revm-primitives 21.0.1", "serde", @@ -7628,7 +7924,7 @@ version = "8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" dependencies = [ - "bitflags", + "bitflags 2.10.0", "revm-bytecode 7.1.1", "revm-primitives 21.0.2", "serde", @@ -7734,6 +8030,35 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rustacuda" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47208516ab5338b592d63560e90eaef405d0ec880347eaf7742d893b0a31e228" +dependencies = [ + "bitflags 1.3.2", + "cuda-driver-sys", + "rustacuda_core", + "rustacuda_derive", +] + +[[package]] +name = "rustacuda_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3858b08976dc2f860c5efbbb48cdcb0d4fafca92a6ac0898465af16c0dbe848" + +[[package]] +name = "rustacuda_derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ce8670a1a1d0fc2514a3b846dacdb65646f9bd494b6674cfacbb4ce430bd7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rustc-demangle" version = "0.1.26" @@ -7782,11 +8107,11 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7819,10 +8144,10 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-platform", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-stark-backend", "rvr-openvm-build", "rvr-openvm-ext-ffi-common", @@ -7834,12 +8159,12 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" [[package]] name = "rvr-openvm-ext-ffi-common" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "openvm-instructions", "openvm-platform", @@ -7848,7 +8173,7 @@ dependencies = [ [[package]] name = "rvr-openvm-ir" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "serde", ] @@ -7856,11 +8181,11 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr#64bfcb2a7c26d5fec95f439cbfd1dd6e8d0d5b17" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "libloading 0.8.9", "openvm-instructions", - "openvm-rv32im-transpiler", + "openvm-riscv-transpiler", "openvm-stark-backend", "rvr-openvm-ext-ffi-common", "rvr-openvm-ir", @@ -8111,7 +8436,7 @@ dependencies = [ "openvm-verify-stark-circuit", "scroll-zkvm-types", "serde_json", - "snark-verifier-sdk", + "snark-verifier-sdk 0.2.1", "toml", ] @@ -8133,7 +8458,7 @@ version = "0.7.1" dependencies = [ "bincode 2.0.1", "ecies", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64)", "openvm", "openvm-algebra-complex-macros", "openvm-algebra-guest", @@ -8142,9 +8467,9 @@ dependencies = [ "openvm-keccak256", "openvm-pairing", "openvm-pairing-guest", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64)", "scroll-zkvm-types-chunk", "scroll-zkvm-types-circuit", ] @@ -8190,7 +8515,7 @@ dependencies = [ "scroll-zkvm-verifier", "serde", "serde_json", - "snark-verifier-sdk", + "snark-verifier-sdk 0.2.1", "sysinfo", "tokio", "toml", @@ -8251,7 +8576,7 @@ dependencies = [ "scroll-zkvm-types-chunk", "serde", "serde_json", - "snark-verifier-sdk", + "snark-verifier-sdk 0.2.1", ] [[package]] @@ -8307,12 +8632,12 @@ dependencies = [ "ecies", "hex-literal 0.4.1", "itertools 0.14.0", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64)", "openvm-ecc-guest", "openvm-pairing", "openvm-pairing-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rvr)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64)", "sbv-core", "sbv-helpers", "sbv-primitives", @@ -8331,7 +8656,7 @@ dependencies = [ "openvm", "openvm-custom-insn", "openvm-deferral-guest", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-verify-stark-guest", "scroll-zkvm-types-base", ] @@ -8353,7 +8678,7 @@ dependencies = [ "serde", "serde_json", "sha256", - "snark-verifier-sdk", + "snark-verifier-sdk 0.2.1", "tracing", ] @@ -8419,7 +8744,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", + "bitflags 2.10.0", "core-foundation", "core-foundation-sys", "libc", @@ -8606,7 +8931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 1.0.4", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -8618,7 +8943,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures", "digest 0.10.7", ] @@ -8653,7 +8978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -8729,8 +9054,8 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d798d8ce8e29b8820ecc1028ac44cc4fc0f0296728af6fe6a0c4db05782c0a4" dependencies = [ - "halo2-base", - "halo2-ecc", + "halo2-base 0.5.0", + "halo2-ecc 0.5.0", "hex", "itertools 0.11.0", "lazy_static", @@ -8745,6 +9070,27 @@ dependencies = [ "sha3", ] +[[package]] +name = "snark-verifier" +version = "0.2.4" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.4#c45e7d357b93d7b040d9e71d2787ba8fa3da2802" +dependencies = [ + "halo2-base 0.5.2", + "halo2-ecc 0.5.2", + "hex", + "itertools 0.11.0", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "pairing 0.23.0", + "rand 0.8.6", + "revm 27.1.0", + "ruint", + "serde", + "sha3", +] + [[package]] name = "snark-verifier-sdk" version = "0.2.1" @@ -8755,7 +9101,29 @@ dependencies = [ "bincode 1.3.3", "ethereum-types", "getset", - "halo2-base", + "halo2-base 0.5.0", + "hex", + "itertools 0.11.0", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.8.6", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "snark-verifier 0.2.1", +] + +[[package]] +name = "snark-verifier-sdk" +version = "0.2.4" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.4#c45e7d357b93d7b040d9e71d2787ba8fa3da2802" +dependencies = [ + "bincode 1.3.3", + "ethereum-types", + "getset", + "halo2-base 0.5.2", "hex", "itertools 0.11.0", "lazy_static", @@ -8766,7 +9134,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_json", - "snark-verifier", + "snark-verifier 0.2.4", ] [[package]] @@ -8784,6 +9152,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spin" @@ -8826,7 +9197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", "libc", "psm", "windows-sys 0.59.0", @@ -9022,7 +9393,16 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", ] [[package]] @@ -9040,7 +9420,7 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "proc-macro2", "quote", "syn 2.0.110", @@ -9104,7 +9484,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -9332,7 +9712,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags", + "bitflags 2.10.0", "bytes", "futures-util", "http", @@ -9657,7 +10037,7 @@ version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -9670,7 +10050,7 @@ version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "once_cell", "wasm-bindgen", @@ -9759,6 +10139,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -10077,6 +10466,16 @@ dependencies = [ "tap", ] +[[package]] +name = "yastl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" +dependencies = [ + "flume", + "scopeguard", +] + [[package]] name = "yoke" version = "0.8.1" @@ -10205,7 +10604,7 @@ dependencies = [ "blake2", "bls12_381", "byteorder", - "cfg-if", + "cfg-if 1.0.4", "group 0.12.1", "group 0.13.0", "halo2", diff --git a/Cargo.toml b/Cargo.toml index 3cca58ae..a08c331c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,50 +26,50 @@ version = "0.8.0" [workspace.dependencies] # openvm guest libs -openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr" } -openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr" } -openvm-sha2-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", package = "p256", features = [ +openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64" } +openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64" } +openvm-sha2-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", package = "p256", features = [ "std", ] } -openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", package = "k256", features = [ +openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", package = "k256", features = [ "std", ] } -openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr" } -openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64" } +openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", package = "openvm-riscv-guest", default-features = false } # openvm host libs -openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-build = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-static-verifier = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-verify-stark-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-build = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-static-verifier = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-verify-stark-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } -openvm-deferral-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } -openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false, features = [ +openvm-deferral-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", package = "openvm-riscv-transpiler", default-features = false } +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false, features = [ "parallel", "evm-prove", "tco", "unprotected" ] } -openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rvr", default-features = false } +openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } # more openvm related libs openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 9740bcc3..d9215d1b 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -425,7 +425,7 @@ fn generate_evm_verifier( let batch_app_config: AppConfig = if batch_config_path.exists() { toml::from_str(&fs::read_to_string(&batch_config_path)?)? } else { - AppConfig::riscv32(app_params.clone()) + AppConfig::riscv64(app_params.clone()) }; let batch_sdk = Sdk::builder() .app_config(batch_app_config) @@ -439,7 +439,7 @@ fn generate_evm_verifier( let bundle_app_config: AppConfig = if bundle_config_path.exists() { toml::from_str(&fs::read_to_string(&bundle_config_path)?)? } else { - AppConfig::riscv32(app_params.clone()) + AppConfig::riscv64(app_params.clone()) }; Sdk::builder() .app_config(bundle_app_config) @@ -448,7 +448,7 @@ fn generate_evm_verifier( .deferral_prover(deferral_prover) .build()? } else { - Sdk::riscv32(app_params, agg_params) + Sdk::riscv64(app_params, agg_params) }; let verifier = if recompute_mode { diff --git a/crates/integration/src/bin/chunk-benchmark.rs b/crates/integration/src/bin/chunk-benchmark.rs index 619ad2f6..a76acd43 100644 --- a/crates/integration/src/bin/chunk-benchmark.rs +++ b/crates/integration/src/bin/chunk-benchmark.rs @@ -8,7 +8,6 @@ use scroll_zkvm_integration::testers::chunk::{ ChunkProverTester, get_witness_from_env_or_builder, preset_chunk, }; use scroll_zkvm_integration::{DIR_TESTRUN, ProverTester, WORKSPACE_ROOT}; -use std::process::Command; use std::{env, fs}; fn main() -> eyre::Result<()> { @@ -35,14 +34,7 @@ fn main() -> eyre::Result<()> { .join("chunk-circuit"); let current_dir = env::current_dir()?; env::set_current_dir(&project_path)?; - let elf = build_elf( - &project_path, - if args.profiling { - "profiling" - } else { - "maxperf" - }, - )?; + let elf = build_elf(&project_path, "maxperf")?; env::set_current_dir(current_dir)?; let wit = get_witness_from_env_or_builder(&mut preset_chunk())?; @@ -55,17 +47,5 @@ fn main() -> eyre::Result<()> { ) })?; - // exec flamegraph generation script - if args.profiling { - Command::new("python3") - .arg(WORKSPACE_ROOT.join("scripts").join("flamegraph.py")) - .arg(metrics_path) - .arg("--guest-symbols") - .arg(symbol_path) - .current_dir(output) - .status()? - .exit_ok()?; - } - Ok(()) } diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index b69d3bf2..d85258a6 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -90,16 +90,17 @@ pub struct ProverConfig { pub segment_len: Option, } +// Kept for API compatibility; RV64 uses memory-based segmentation instead of trace-height limit. +#[allow(dead_code)] const DEFAULT_SEGMENT_SIZE: usize = (1 << 22) - 1000; impl Prover { /// Setup the [`Prover`] given paths to the application's exe and proving key. #[instrument("Prover::setup")] pub fn setup(config: ProverConfig, name: Option<&str>) -> Result { - let mut app_config = read_app_config(&config.path_app_config)?; - let segment_len = config.segment_len.unwrap_or(DEFAULT_SEGMENT_SIZE); - let segmentation_limits = &mut app_config.app_vm_config.system.config.segmentation_limits; - segmentation_limits.max_trace_height = segment_len as u32; + let app_config = read_app_config(&config.path_app_config)?; + // RV64 uses memory-based segmentation; trace-height limit no longer exists. + // The segment_len config field is kept for API compatibility. let app_exe = read_app_exe(&config.path_app_exe)?; Ok(Self { diff --git a/crates/prover/src/utils/vm.rs b/crates/prover/src/utils/vm.rs index a7babe03..3c31c54e 100644 --- a/crates/prover/src/utils/vm.rs +++ b/crates/prover/src/utils/vm.rs @@ -26,7 +26,7 @@ pub fn execute_guest( tracing::info!("Double preset max cost to ({preset_max_cost}) for metering execution"); compiled.ctx = compiled.ctx.with_max_execution_cost(preset_max_cost); let (mut public_values, (cost, instret)) = - sdk.execute_compiled_metered_cost(&compiled, inputs.clone())?; + sdk.execute_metered_cost(&compiled, inputs.clone())?; let mut total_cycle = instret; if public_values.iter().all(|x| *x == 0) { @@ -39,7 +39,8 @@ pub fn execute_guest( tracing::warn!( "Large execution exceed limit of metered execution, cycle is expected to >{estimated_max_cycles}" ); - public_values = sdk.execute(exe, inputs.clone())?; + let compiled_pure = sdk.compile(exe)?; + public_values = sdk.execute(&compiled_pure, inputs.clone())?; total_cycle = estimated_max_cycles; if public_values.iter().all(|x| *x == 0) { diff --git a/crates/types/circuit/src/io.rs b/crates/types/circuit/src/io.rs index 8a368d7d..7c51cf23 100644 --- a/crates/types/circuit/src/io.rs +++ b/crates/types/circuit/src/io.rs @@ -1,33 +1,7 @@ #[allow(unused_imports, clippy::single_component_path_imports)] use openvm::platform as openvm_platform; -/// Read the witnesses from the hint stream. -/// -/// rkyv needs special alignment for its data structures, use a pre-aligned buffer with rkyv::access_unchecked -/// is more efficient than rkyv::access. -#[cfg(target_os = "zkvm")] -#[inline(always)] -pub fn read_witnesses_rkyv_raw() -> Vec { - use std::alloc::{GlobalAlloc, Layout, System}; - openvm_rv32im_guest::hint_input(); - let mut len: u32 = 0; - openvm_rv32im_guest::hint_store_u32!((&mut len) as *mut u32 as u32); - let num_words = len.div_ceil(4); - let size = (num_words * 4) as usize; - let layout = Layout::from_size_align(size, 16).unwrap(); - let ptr_start = unsafe { System.alloc(layout) }; - let mut ptr = ptr_start; - for _ in 0..num_words { - openvm_rv32im_guest::hint_store_u32!(ptr as u32); - ptr = unsafe { ptr.add(4) }; - } - unsafe { Vec::from_raw_parts(ptr_start, len as usize, size) } -} - /// Read the witnesses from the hint stream. pub fn read_witnesses() -> Vec { - #[cfg(not(target_os = "zkvm"))] - return openvm::io::read_vec(); // avoid compiler complaint - #[cfg(target_os = "zkvm")] - return read_witnesses_rkyv_raw(); + openvm::io::read_vec() } diff --git a/crates/types/src/zkvm.rs b/crates/types/src/zkvm.rs index 64826f98..f103758f 100644 --- a/crates/types/src/zkvm.rs +++ b/crates/types/src/zkvm.rs @@ -19,5 +19,5 @@ fn build_agg_pk() -> AggProvingKey { leaf: leaf_params_with_100_bits_security(), internal: internal_params_with_100_bits_security(), }; - Sdk::riscv32(app_params, agg_params).agg_pk().clone() + Sdk::riscv64(app_params, agg_params).agg_pk().clone() } From 9b3dabac2417108196fab45c300201def22789c7 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Mon, 22 Jun 2026 06:52:28 +0800 Subject: [PATCH 17/19] chore: complete openvm rv64 switch and fix EVM verifier - Switch to develop-v2.1.0-rv64 with local patches - Fix user public value limb handling for rv64 in OpenVmHalo2Verifier (reverse little-endian u16 limbs into EVM big-endian Fr words) - Fix verify_wrapped_proof return type handling - Regenerate guest assets and EVM verifier - Pass GPU bundle e2e test --- Cargo.lock | 735 ++------ Cargo.toml | 15 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- crates/circuits/batch-circuit/openvm.toml | 4 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- crates/circuits/bundle-circuit/openvm.toml | 4 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/circuits/chunk-circuit/openvm.toml | 4 +- crates/prover/Cargo.toml | 7 +- crates/types/batch/Cargo.toml | 2 +- crates/types/chunk/src/scroll/execute.rs | 2 +- crates/types/circuit/src/lib.rs | 19 +- crates/verifier/src/verifier.rs | 5 +- patches/openvm-sdk/Cargo.toml | 136 ++ patches/openvm-sdk/contracts/.gitignore | 14 + .../contracts/abi/IOpenVmHalo2Verifier.json | 30 + patches/openvm-sdk/contracts/foundry.toml | 31 + patches/openvm-sdk/contracts/lib/.gitignore | 1 + .../contracts/src/IOpenVmHalo2Verifier.sol | 8 + .../template/OpenVmHalo2Verifier.sol | 154 ++ .../contracts/test/OpenVmHalo2Verifier.t.sol | 161 ++ .../contracts/test/helpers/LibString.sol | 1628 +++++++++++++++++ .../contracts/test/helpers/MockDeps.sol | 12 + patches/openvm-sdk/examples/sdk_app.rs | 45 + patches/openvm-sdk/examples/sdk_evm.rs | 71 + patches/openvm-sdk/examples/sdk_stark.rs | 79 + patches/openvm-sdk/guest/fib/Cargo.toml | 17 + patches/openvm-sdk/guest/fib/openvm.toml | 3 + patches/openvm-sdk/guest/fib/src/main.rs | 40 + patches/openvm-sdk/guest/little/Cargo.toml | 25 + patches/openvm-sdk/guest/little/openvm.toml | 72 + .../openvm-sdk/guest/little/openvm_init.rs | 4 + patches/openvm-sdk/guest/little/src/main.rs | 49 + patches/openvm-sdk/guest/p256/Cargo.toml | 31 + patches/openvm-sdk/guest/p256/openvm.toml | 72 + patches/openvm-sdk/guest/p256/openvm_init.rs | 4 + patches/openvm-sdk/guest/p256/src/main.rs | 42 + patches/openvm-sdk/openvm_riscv64.toml | 3 + patches/openvm-sdk/openvm_standard.toml | 72 + patches/openvm-sdk/programs/Cargo.toml | 23 + .../programs/examples/fibonacci.elf | Bin 0 -> 49008 bytes .../openvm-sdk/programs/examples/fibonacci.rs | 21 + .../programs/examples/verify-many.elf | Bin 0 -> 139992 bytes .../programs/examples/verify-many.rs | 33 + .../programs/examples/verify-stark.elf | Bin 0 -> 141928 bytes .../programs/examples/verify-stark.rs | 30 + patches/openvm-sdk/src/builder.rs | 562 ++++++ patches/openvm-sdk/src/compiled.rs | 66 + patches/openvm-sdk/src/config.rs | 112 ++ patches/openvm-sdk/src/error.rs | 32 + patches/openvm-sdk/src/fs.rs | 217 +++ patches/openvm-sdk/src/halo2_params.rs | 59 + patches/openvm-sdk/src/keygen/dummy.rs | 149 ++ patches/openvm-sdk/src/keygen/mod.rs | 139 ++ patches/openvm-sdk/src/keygen/perm.rs | 93 + .../openvm-sdk/src/keygen/static_verifier.rs | 70 + patches/openvm-sdk/src/lib.rs | 882 +++++++++ patches/openvm-sdk/src/prover/agg.rs | 484 +++++ patches/openvm-sdk/src/prover/app.rs | 209 +++ .../openvm-sdk/src/prover/deferral/circuit.rs | 162 ++ .../openvm-sdk/src/prover/deferral/merkle.rs | 65 + patches/openvm-sdk/src/prover/deferral/mod.rs | 264 +++ .../src/prover/deferral/verify_stark.rs | 116 ++ patches/openvm-sdk/src/prover/evm.rs | 127 ++ patches/openvm-sdk/src/prover/halo2.rs | 56 + patches/openvm-sdk/src/prover/mod.rs | 22 + patches/openvm-sdk/src/prover/root.rs | 238 +++ patches/openvm-sdk/src/prover/stark.rs | 196 ++ patches/openvm-sdk/src/prover/vm/mod.rs | 27 + patches/openvm-sdk/src/prover/vm/types.rs | 18 + patches/openvm-sdk/src/solidity.rs | 283 +++ patches/openvm-sdk/src/stdin.rs | 86 + patches/openvm-sdk/src/tests.rs | 843 +++++++++ patches/openvm-sdk/src/types.rs | 502 +++++ patches/openvm-sdk/src/util.rs | 23 + patches/openvm-static-verifier/Cargo.toml | 43 + patches/openvm-static-verifier/src/circuit.rs | 302 +++ patches/openvm-static-verifier/src/codec.rs | 99 + patches/openvm-static-verifier/src/config.rs | 39 + .../src/context_tree.rs | 187 ++ .../src/field/baby_bear/base.rs | 596 ++++++ .../src/field/baby_bear/extension.rs | 358 ++++ .../src/field/baby_bear/mod.rs | 16 + .../src/field/baby_bear/tests.rs | 203 ++ .../openvm-static-verifier/src/field/mod.rs | 1 + .../openvm-static-verifier/src/hash/mod.rs | 64 + .../src/hash/poseidon2.rs | 238 +++ patches/openvm-static-verifier/src/keygen.rs | 198 ++ patches/openvm-static-verifier/src/lib.rs | 49 + .../openvm-static-verifier/src/profiling.rs | 83 + patches/openvm-static-verifier/src/prover.rs | 180 ++ .../src/stages/batch_constraints/mod.rs | 1189 ++++++++++++ .../src/stages/full_pipeline/mod.rs | 321 ++++ .../src/stages/full_pipeline/public_values.rs | 84 + .../src/stages/full_pipeline/tests.rs | 267 +++ .../openvm-static-verifier/src/stages/mod.rs | 6 + .../src/stages/proof_shape/mod.rs | 40 + .../src/stages/shared_math.rs | 99 + .../src/stages/stacked_reduction/mod.rs | 318 ++++ .../src/stages/whir/mod.rs | 735 ++++++++ .../src/transcript/mod.rs | 377 ++++ .../src/transcript/tests.rs | 281 +++ patches/openvm-static-verifier/src/utils.rs | 72 + patches/openvm-static-verifier/src/wrapper.rs | 288 +++ .../tests/real_prover_roundtrip.rs | 177 ++ releases/dev/verifier/Halo2Verifier.sol | 14 +- releases/dev/verifier/verifier.bin | Bin 19405 -> 19459 bytes releases/dev/verifier/verifier.sol | 39 +- 111 files changed, 16135 insertions(+), 650 deletions(-) create mode 100644 patches/openvm-sdk/Cargo.toml create mode 100644 patches/openvm-sdk/contracts/.gitignore create mode 100644 patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json create mode 100644 patches/openvm-sdk/contracts/foundry.toml create mode 100644 patches/openvm-sdk/contracts/lib/.gitignore create mode 100644 patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol create mode 100644 patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol create mode 100644 patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol create mode 100644 patches/openvm-sdk/contracts/test/helpers/LibString.sol create mode 100644 patches/openvm-sdk/contracts/test/helpers/MockDeps.sol create mode 100644 patches/openvm-sdk/examples/sdk_app.rs create mode 100644 patches/openvm-sdk/examples/sdk_evm.rs create mode 100644 patches/openvm-sdk/examples/sdk_stark.rs create mode 100644 patches/openvm-sdk/guest/fib/Cargo.toml create mode 100644 patches/openvm-sdk/guest/fib/openvm.toml create mode 100644 patches/openvm-sdk/guest/fib/src/main.rs create mode 100644 patches/openvm-sdk/guest/little/Cargo.toml create mode 100644 patches/openvm-sdk/guest/little/openvm.toml create mode 100644 patches/openvm-sdk/guest/little/openvm_init.rs create mode 100644 patches/openvm-sdk/guest/little/src/main.rs create mode 100644 patches/openvm-sdk/guest/p256/Cargo.toml create mode 100644 patches/openvm-sdk/guest/p256/openvm.toml create mode 100644 patches/openvm-sdk/guest/p256/openvm_init.rs create mode 100644 patches/openvm-sdk/guest/p256/src/main.rs create mode 100644 patches/openvm-sdk/openvm_riscv64.toml create mode 100644 patches/openvm-sdk/openvm_standard.toml create mode 100644 patches/openvm-sdk/programs/Cargo.toml create mode 100755 patches/openvm-sdk/programs/examples/fibonacci.elf create mode 100644 patches/openvm-sdk/programs/examples/fibonacci.rs create mode 100755 patches/openvm-sdk/programs/examples/verify-many.elf create mode 100644 patches/openvm-sdk/programs/examples/verify-many.rs create mode 100644 patches/openvm-sdk/programs/examples/verify-stark.elf create mode 100644 patches/openvm-sdk/programs/examples/verify-stark.rs create mode 100644 patches/openvm-sdk/src/builder.rs create mode 100644 patches/openvm-sdk/src/compiled.rs create mode 100644 patches/openvm-sdk/src/config.rs create mode 100644 patches/openvm-sdk/src/error.rs create mode 100644 patches/openvm-sdk/src/fs.rs create mode 100644 patches/openvm-sdk/src/halo2_params.rs create mode 100644 patches/openvm-sdk/src/keygen/dummy.rs create mode 100644 patches/openvm-sdk/src/keygen/mod.rs create mode 100644 patches/openvm-sdk/src/keygen/perm.rs create mode 100644 patches/openvm-sdk/src/keygen/static_verifier.rs create mode 100644 patches/openvm-sdk/src/lib.rs create mode 100644 patches/openvm-sdk/src/prover/agg.rs create mode 100644 patches/openvm-sdk/src/prover/app.rs create mode 100644 patches/openvm-sdk/src/prover/deferral/circuit.rs create mode 100644 patches/openvm-sdk/src/prover/deferral/merkle.rs create mode 100644 patches/openvm-sdk/src/prover/deferral/mod.rs create mode 100644 patches/openvm-sdk/src/prover/deferral/verify_stark.rs create mode 100644 patches/openvm-sdk/src/prover/evm.rs create mode 100644 patches/openvm-sdk/src/prover/halo2.rs create mode 100644 patches/openvm-sdk/src/prover/mod.rs create mode 100644 patches/openvm-sdk/src/prover/root.rs create mode 100644 patches/openvm-sdk/src/prover/stark.rs create mode 100644 patches/openvm-sdk/src/prover/vm/mod.rs create mode 100644 patches/openvm-sdk/src/prover/vm/types.rs create mode 100644 patches/openvm-sdk/src/solidity.rs create mode 100644 patches/openvm-sdk/src/stdin.rs create mode 100644 patches/openvm-sdk/src/tests.rs create mode 100644 patches/openvm-sdk/src/types.rs create mode 100644 patches/openvm-sdk/src/util.rs create mode 100644 patches/openvm-static-verifier/Cargo.toml create mode 100644 patches/openvm-static-verifier/src/circuit.rs create mode 100644 patches/openvm-static-verifier/src/codec.rs create mode 100644 patches/openvm-static-verifier/src/config.rs create mode 100644 patches/openvm-static-verifier/src/context_tree.rs create mode 100644 patches/openvm-static-verifier/src/field/baby_bear/base.rs create mode 100644 patches/openvm-static-verifier/src/field/baby_bear/extension.rs create mode 100644 patches/openvm-static-verifier/src/field/baby_bear/mod.rs create mode 100644 patches/openvm-static-verifier/src/field/baby_bear/tests.rs create mode 100644 patches/openvm-static-verifier/src/field/mod.rs create mode 100644 patches/openvm-static-verifier/src/hash/mod.rs create mode 100644 patches/openvm-static-verifier/src/hash/poseidon2.rs create mode 100644 patches/openvm-static-verifier/src/keygen.rs create mode 100644 patches/openvm-static-verifier/src/lib.rs create mode 100644 patches/openvm-static-verifier/src/profiling.rs create mode 100644 patches/openvm-static-verifier/src/prover.rs create mode 100644 patches/openvm-static-verifier/src/stages/batch_constraints/mod.rs create mode 100644 patches/openvm-static-verifier/src/stages/full_pipeline/mod.rs create mode 100644 patches/openvm-static-verifier/src/stages/full_pipeline/public_values.rs create mode 100644 patches/openvm-static-verifier/src/stages/full_pipeline/tests.rs create mode 100644 patches/openvm-static-verifier/src/stages/mod.rs create mode 100644 patches/openvm-static-verifier/src/stages/proof_shape/mod.rs create mode 100644 patches/openvm-static-verifier/src/stages/shared_math.rs create mode 100644 patches/openvm-static-verifier/src/stages/stacked_reduction/mod.rs create mode 100644 patches/openvm-static-verifier/src/stages/whir/mod.rs create mode 100644 patches/openvm-static-verifier/src/transcript/mod.rs create mode 100644 patches/openvm-static-verifier/src/transcript/tests.rs create mode 100644 patches/openvm-static-verifier/src/utils.rs create mode 100644 patches/openvm-static-verifier/src/wrapper.rs create mode 100644 patches/openvm-static-verifier/tests/real_prover_roundtrip.rs diff --git a/Cargo.lock b/Cargo.lock index af9c45e6..887f5220 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ version = "0.9.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e713c57c2a2b19159e7be83b9194600d7e8eb3b7c2cd67e671adf47ce189a05" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "cipher", "cpufeatures", ] @@ -106,8 +106,7 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if 1.0.4", - "getrandom 0.3.4", + "cfg-if", "once_cell", "version_check", "zerocopy", @@ -147,10 +146,10 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad704069c12f68d0c742d0cad7e0a03882b42767350584627fbf8a47b1bf1846" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "alloy-trie 0.9.1", "alloy-tx-macros", "auto_impl", @@ -175,10 +174,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc374f640a5062224d7708402728e3d6879a514ba10f377da62e7dfb14c673e6" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "serde", ] @@ -222,26 +221,6 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "alloy-eips" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609515c1955b33af3d78d26357540f68c5551a90ef58fd53def04f2aa074ec43" -dependencies = [ - "alloy-eip2124", - "alloy-eip2930", - "alloy-eip7702", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.14.0", - "auto_impl", - "c-kzg", - "derive_more 2.0.1", - "either", - "serde", - "sha2 0.10.9", -] - [[package]] name = "alloy-eips" version = "1.1.1" @@ -253,7 +232,7 @@ dependencies = [ "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "auto_impl", "borsh", "c-kzg", @@ -274,7 +253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08e9e656d58027542447c1ca5aa4ca96293f09e6920c4651953b7451a7c35e4e" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-hardforks", "alloy-primitives", "alloy-rpc-types-engine", @@ -295,9 +274,9 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b90be17e9760a6ba6d13cebdb049cea405ebc8bf57d90664ed708cc5bc348342" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", - "alloy-serde 1.1.1", + "alloy-serde", "alloy-trie 0.9.1", "borsh", "serde", @@ -353,13 +332,13 @@ checksum = "196d7fd3f5d414f7bbd5886a628b7c42bd98d1b126f9a7cff69dbfd72007b39c" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde 1.1.1", + "alloy-serde", "alloy-signer", "alloy-sol-types", "async-trait", @@ -378,9 +357,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d3ae2777e900a7a47ad9e3b8ab58eff3d93628265e73bbdee09acf90bf68f75" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", - "alloy-serde 1.1.1", + "alloy-serde", "serde", ] @@ -392,7 +371,7 @@ checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" dependencies = [ "alloy-rlp", "bytes", - "cfg-if 1.0.4", + "cfg-if", "const-hex", "derive_more 2.0.1", "foldhash 0.2.0", @@ -419,7 +398,7 @@ checksum = "9f9bf40c9b2a90c7677f9c39bccd9f06af457f35362439c0497a706f16557703" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-json-rpc", "alloy-network", "alloy-network-primitives", @@ -503,7 +482,7 @@ checksum = "50b8429b5b62d21bf3691eb1ae12aaae9bb496894d5a114e3cc73e27e6800ec8" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde 1.1.1", + "alloy-serde", ] [[package]] @@ -525,10 +504,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9981491bb98e76099983f516ec7de550db0597031f5828c994961eb4bb993cce" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "derive_more 2.0.1", "ethereum_ssz", "ethereum_ssz_derive", @@ -544,11 +523,11 @@ checksum = "29031a6bf46177d65efce661f7ab37829ca09dd341bc40afb5194e97600655cc" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "alloy-sol-types", "itertools 0.14.0", "serde", @@ -557,17 +536,6 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "alloy-serde" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4dba6ff08916bc0a9cbba121ce21f67c0b554c39cf174bc7b9df6c651bd3c3b" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - [[package]] name = "alloy-serde" version = "1.1.1" @@ -1187,17 +1155,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "aurora-engine-modexp" version = "1.2.0" @@ -1238,7 +1195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cfg-if 1.0.4", + "cfg-if", "libc", "miniz_oxide", "object 0.37.3", @@ -1335,12 +1292,6 @@ dependencies = [ "hex-conservative", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.10.0" @@ -1626,12 +1577,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.4" @@ -1740,7 +1685,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "cpufeatures", "proptest", "serde_core", @@ -1997,24 +1942,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "cuda-config" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee74643f7430213a1a78320f88649de309b20b80818325575e393f848f79f5d" -dependencies = [ - "glob", -] - -[[package]] -name = "cuda-driver-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4c552cc0de854877d80bcd1f11db75d42be32962d72a6799b88dcca88fffbd" -dependencies = [ - "cuda-config", -] - [[package]] name = "cudarc" version = "0.9.15" @@ -2098,7 +2025,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", @@ -2417,19 +2344,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -2587,15 +2501,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "spin 0.9.8", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2751,7 +2656,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", ] [[package]] @@ -2771,7 +2676,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "libc", "wasi", ] @@ -2782,7 +2687,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "js-sys", "libc", "r-efi", @@ -2859,7 +2764,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "futures-sink", "futures-timer", "futures-util", @@ -2930,66 +2835,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "halo2-axiom-gpu" -version = "1.0.0-rc.0" -source = "git+https://github.com/axiom-crypto/halo2-gpu.git?tag=v1.0.0-rc.0#fa3d662335d8f913660460d443509a84d1f3242f" -dependencies = [ - "ahash", - "anyhow", - "ark-std 0.3.0", - "blake2b_simd", - "cfg-if 0.1.10", - "colored", - "crossbeam", - "cuda-driver-sys", - "env_logger", - "ff 0.13.1", - "git-version", - "group 0.13.0", - "halo2curves-axiom 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.11.0", - "lazy_static", - "libc", - "log", - "num-bigint", - "num-integer", - "once_cell", - "openvm-cuda-builder", - "openvm-cuda-common", - "pairing 0.23.0", - "rand 0.8.6", - "rand_core 0.6.4", - "rayon", - "rustacuda", - "rustc-hash 1.1.0", - "sha3", - "subtle", - "tracing", - "yastl", -] - -[[package]] -name = "halo2-base" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678cf3adc0a39d7b4d9b82315a655201aa24a430dd1902b162c508047f56ac69" -dependencies = [ - "getset", - "halo2-axiom", - "itertools 0.11.0", - "log", - "num-bigint", - "num-integer", - "num-traits", - "poseidon-primitives", - "rand_chacha 0.3.1", - "rayon", - "rustc-hash 1.1.0", - "serde", - "serde_json", -] - [[package]] name = "halo2-base" version = "0.5.2" @@ -2997,7 +2842,6 @@ source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.2#b4031ae0a dependencies = [ "getset", "halo2-axiom", - "halo2-axiom-gpu", "itertools 0.11.0", "log", "num-bigint", @@ -3011,32 +2855,12 @@ dependencies = [ "serde_json", ] -[[package]] -name = "halo2-ecc" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c00681fdd1febaf552d8814e9f5a6a142d81a1514102190da07039588b366" -dependencies = [ - "halo2-base 0.5.0", - "itertools 0.11.0", - "num-bigint", - "num-integer", - "num-traits", - "rand 0.8.6", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "rayon", - "serde", - "serde_json", - "test-case", -] - [[package]] name = "halo2-ecc" version = "0.5.2" source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.2#b4031ae0adb7cb37650ebd85c40631d8fca44237" dependencies = [ - "halo2-base 0.5.2", + "halo2-base", "itertools 0.11.0", "num-bigint", "num-integer", @@ -3167,15 +2991,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.5.2" @@ -3270,15 +3085,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "hybrid-array" version = "0.4.5" @@ -3643,7 +3449,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "ecdsa", "elliptic-curve", "once_cell", @@ -3711,7 +3517,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "winapi", ] @@ -3721,7 +3527,7 @@ version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "windows-link 0.2.1", ] @@ -3864,7 +3670,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "rayon", ] @@ -4162,7 +3968,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.5.2", + "hermit-abi", "libc", ] @@ -4217,7 +4023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" dependencies = [ "alloy-rlp", - "cfg-if 1.0.4", + "cfg-if", "proptest", "ruint", "serde", @@ -4230,7 +4036,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -4284,10 +4090,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a501241474c3118833d6195312ae7eb7cc90bbb0d5f524cbb0b06619e49ff67" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "derive_more 2.0.1", "serde", "serde_with", @@ -4301,7 +4107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d7ec388eb83a3e6c71774131dbbb2ba9c199b6acac7dce172ed8de2f819e91" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", "derive_more 2.0.1", @@ -4315,7 +4121,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1abe694cd6718b8932da3f824f46778be0f43289e4103c88abc505c63533a04" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -4350,8 +4156,8 @@ version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ - "bitflags 2.10.0", - "cfg-if 1.0.4", + "bitflags", + "cfg-if", "foreign-types", "libc", "openssl-macros", @@ -4408,7 +4214,7 @@ version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "blstrs", - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -4541,7 +4347,7 @@ name = "openvm-bigint-circuit" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "openvm-bigint-transpiler", @@ -4607,7 +4413,7 @@ dependencies = [ "abi_stable", "backtrace", "bytesize", - "cfg-if 1.0.4", + "cfg-if", "dashmap", "derive-new 0.6.0", "derive_more 1.0.0", @@ -4698,7 +4504,7 @@ name = "openvm-continuations" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "eyre", "itertools 0.14.0", @@ -4726,7 +4532,7 @@ name = "openvm-cpu-backend" version = "2.0.0-alpha" source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.7.0", "getset", "itertools 0.14.0", @@ -4816,7 +4622,7 @@ name = "openvm-deferral-circuit" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "dashmap", "derive-new 0.6.0", "derive_more 1.0.0", @@ -4872,7 +4678,7 @@ version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "blstrs", - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", @@ -5084,7 +4890,7 @@ name = "openvm-pairing-circuit" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -5232,7 +5038,7 @@ name = "openvm-riscv-circuit" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -5284,18 +5090,17 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "alloy-sol-types", "bitcode", - "cfg-if 1.0.4", + "cfg-if", "clap", "derivative", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", "getset", - "halo2-base 0.5.2", + "halo2-base", "hex", "itertools 0.14.0", "openvm", @@ -5326,7 +5131,7 @@ version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "bon", - "cfg-if 1.0.4", + "cfg-if", "derive_more 1.0.0", "openvm-algebra-circuit", "openvm-algebra-transpiler", @@ -5382,7 +5187,7 @@ name = "openvm-sha2-circuit" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "itertools 0.14.0", @@ -5433,7 +5238,7 @@ name = "openvm-stark-backend" version = "2.0.0-alpha" source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2#d1723198c81562157c922d9d06c035e9dcad91e2" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derivative", "derive-new 0.7.0", "eyre", @@ -5495,9 +5300,8 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0-beta.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "halo2-base 0.5.2", + "halo2-base", "itertools 0.14.0", "num-bigint", "num-integer", @@ -5512,7 +5316,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "snark-verifier-sdk 0.2.4", + "snark-verifier-sdk", "tracing", ] @@ -5536,7 +5340,7 @@ name = "openvm-verify-stark-circuit" version = "2.0.0-beta.2" source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-new 0.6.0", "eyre", "itertools 0.14.0", @@ -5908,7 +5712,7 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -6107,7 +5911,7 @@ version = "0.7.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffd40cc99d0fbb02b4b3771346b811df94194bc103983efa0203c8893755085" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "cpufeatures", "universal-hash", ] @@ -6266,7 +6070,7 @@ checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags", "num-traits", "rand 0.9.4", "rand_chacha 0.9.0", @@ -6425,7 +6229,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -6460,7 +6264,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -6564,7 +6368,7 @@ source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186d dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-genesis", "alloy-primitives", @@ -6583,7 +6387,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-genesis", "alloy-primitives", "alloy-trie 0.9.1", @@ -6624,7 +6428,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "reth-chainspec", "reth-consensus", "reth-primitives-traits", @@ -6635,7 +6439,7 @@ name = "reth-db-models" version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "reth-primitives-traits", ] @@ -6657,7 +6461,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -6685,11 +6489,11 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde 1.1.1", + "alloy-serde", "reth-codecs", "reth-primitives-traits", "serde", @@ -6702,7 +6506,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-primitives", "auto_impl", @@ -6724,7 +6528,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", @@ -6757,7 +6561,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-primitives", "derive_more 2.0.1", @@ -6798,7 +6602,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-genesis", "alloy-primitives", "alloy-rlp", @@ -6849,10 +6653,10 @@ source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186d dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-genesis", "alloy-primitives", - "alloy-serde 1.1.1", + "alloy-serde", "auto_impl", "derive_more 2.0.1", "once_cell", @@ -6873,7 +6677,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", @@ -6917,7 +6721,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", "bytes", @@ -6980,7 +6784,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "auto_impl", @@ -7001,7 +6805,7 @@ name = "reth-storage-errors" version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", "derive_more 2.0.1", @@ -7018,7 +6822,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-trie 0.9.1", @@ -7074,25 +6878,6 @@ dependencies = [ "zstd", ] -[[package]] -name = "revm" -version = "22.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5378e95ffe5c8377002dafeb6f7d370a55517cef7d6d6c16fc552253af3b123" -dependencies = [ - "revm-bytecode 3.0.0", - "revm-context 3.0.1", - "revm-context-interface 3.0.0", - "revm-database 3.0.0", - "revm-database-interface 3.0.0", - "revm-handler 3.0.1", - "revm-inspector 3.0.1", - "revm-interpreter 18.0.0", - "revm-precompile 19.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", -] - [[package]] name = "revm" version = "27.1.0" @@ -7168,18 +6953,6 @@ dependencies = [ "revm-state 8.1.1", ] -[[package]] -name = "revm-bytecode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e138d520c5c5bc25ecc82506e9e4e6e85a811809fc5251c594378dccabfc6" -dependencies = [ - "bitvec", - "phf 0.11.3", - "revm-primitives 18.0.0", - "serde", -] - [[package]] name = "revm-bytecode" version = "6.2.2" @@ -7215,29 +6988,13 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-context" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9765628dfea4f3686aa8f2a72471c52801e6b38b601939ac16965f49bac66580" -dependencies = [ - "cfg-if 1.0.4", - "derive-where", - "revm-bytecode 3.0.0", - "revm-context-interface 3.0.0", - "revm-database-interface 3.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", - "serde", -] - [[package]] name = "revm-context" version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cd508416a35a4d8a9feaf5ccd06ac6d6661cd31ee2dc0252f9f7316455d71f9" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "derive-where", "revm-bytecode 6.2.2", "revm-context-interface 9.0.0", @@ -7254,7 +7011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a20c98e7008591a6f012550c2a00aa36cba8c14cc88eb88dec32eb9102554b4" dependencies = [ "bitvec", - "cfg-if 1.0.4", + "cfg-if", "derive-where", "revm-bytecode 6.2.2", "revm-context-interface 10.2.0", @@ -7270,7 +7027,7 @@ version = "10.1.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ "bitvec", - "cfg-if 1.0.4", + "cfg-if", "derive-where", "revm-bytecode 7.0.1", "revm-context-interface 11.1.1", @@ -7287,7 +7044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7adcce0c14cf59b7128de34185a0fbf8f63309539b9263b35ead870d73584114" dependencies = [ "bitvec", - "cfg-if 1.0.4", + "cfg-if", "derive-where", "revm-bytecode 7.1.1", "revm-context-interface 11.1.2", @@ -7297,21 +7054,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-context-interface" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d74335aa1f14222cc4d3be1f62a029cc7dc03819cc8d080ff17b7e1d76375f" -dependencies = [ - "alloy-eip2930", - "alloy-eip7702", - "auto_impl", - "revm-database-interface 3.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", - "serde", -] - [[package]] name = "revm-context-interface" version = "9.0.0" @@ -7375,27 +7117,13 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-database" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5c80c5a2fd605f2119ee32a63fb3be941fb6a81ced8cdb3397abca28317224" -dependencies = [ - "alloy-eips 0.14.0", - "revm-bytecode 3.0.0", - "revm-database-interface 3.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", - "serde", -] - [[package]] name = "revm-database" version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39a276ed142b4718dcf64bc9624f474373ed82ef20611025045c3fb23edbef9c" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "revm-bytecode 6.2.2", "revm-database-interface 7.0.5", "revm-primitives 20.2.1", @@ -7408,7 +7136,7 @@ name = "revm-database" version = "9.0.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "revm-bytecode 7.0.1", "revm-database-interface 8.0.2", "revm-primitives 21.0.1", @@ -7422,7 +7150,7 @@ version = "9.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "980d8d6bba78c5dd35b83abbb6585b0b902eb25ea4448ed7bfba6283b0337191" dependencies = [ - "alloy-eips 1.1.1", + "alloy-eips", "revm-bytecode 7.1.1", "revm-database-interface 8.0.5", "revm-primitives 21.0.2", @@ -7430,18 +7158,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-database-interface" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e4dfbc734b1ea67b5e8f8b3c7dc4283e2210d978cdaf6c7a45e97be5ea53b3" -dependencies = [ - "auto_impl", - "revm-primitives 18.0.0", - "revm-state 3.0.0", - "serde", -] - [[package]] name = "revm-database-interface" version = "7.0.5" @@ -7480,24 +7196,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-handler" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8676379521c7bf179c31b685c5126ce7800eab5844122aef3231b97026d41a10" -dependencies = [ - "auto_impl", - "revm-bytecode 3.0.0", - "revm-context 3.0.1", - "revm-context-interface 3.0.0", - "revm-database-interface 3.0.0", - "revm-interpreter 18.0.0", - "revm-precompile 19.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", - "serde", -] - [[package]] name = "revm-handler" version = "8.1.0" @@ -7573,23 +7271,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-inspector" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfed4ecf999a3f6ae776ae2d160478c5dca986a8c2d02168e04066b1e34c789e" -dependencies = [ - "auto_impl", - "revm-context 3.0.1", - "revm-database-interface 3.0.0", - "revm-handler 3.0.1", - "revm-interpreter 18.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", - "serde", - "serde_json", -] - [[package]] name = "revm-inspector" version = "8.1.0" @@ -7661,18 +7342,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "revm-interpreter" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb20260342003cfb791536e678ef5bbea1bfd1f8178b170e8885ff821985473" -dependencies = [ - "revm-bytecode 3.0.0", - "revm-context-interface 3.0.0", - "revm-primitives 18.0.0", - "serde", -] - [[package]] name = "revm-interpreter" version = "24.0.0" @@ -7722,31 +7391,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-precompile" -version = "19.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418e95eba68c9806c74f3e36cd5d2259170b61e90ac608b17ff8c435038ddace" -dependencies = [ - "ark-bls12-381", - "ark-bn254", - "ark-ec", - "ark-ff 0.5.0", - "ark-serialize 0.5.0", - "aurora-engine-modexp", - "blst", - "c-kzg", - "cfg-if 1.0.4", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1", - "once_cell", - "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", - "revm-primitives 18.0.0", - "ripemd", - "secp256k1 0.30.0", - "sha2 0.10.9", -] - [[package]] name = "revm-precompile" version = "25.0.0" @@ -7762,7 +7406,7 @@ dependencies = [ "aurora-engine-modexp", "blst", "c-kzg", - "cfg-if 1.0.4", + "cfg-if", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1", "once_cell", @@ -7789,7 +7433,7 @@ dependencies = [ "aurora-engine-modexp", "blst", "c-kzg", - "cfg-if 1.0.4", + "cfg-if", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -7813,7 +7457,7 @@ dependencies = [ "arrayref", "aurora-engine-modexp", "c-kzg", - "cfg-if 1.0.4", + "cfg-if", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", "revm-primitives 21.0.1", @@ -7823,17 +7467,6 @@ dependencies = [ "sha2 0.10.9", ] -[[package]] -name = "revm-primitives" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc2283ff87358ec7501956c5dd8724a6c2be959c619c4861395ae5e0054575f" -dependencies = [ - "alloy-primitives", - "enumn", - "serde", -] - [[package]] name = "revm-primitives" version = "20.2.1" @@ -7883,25 +7516,13 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-state" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dd121f6e66d75ab111fb51b4712f129511569bc3e41e6067ae760861418bd8" -dependencies = [ - "bitflags 2.10.0", - "revm-bytecode 3.0.0", - "revm-primitives 18.0.0", - "serde", -] - [[package]] name = "revm-state" version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" dependencies = [ - "bitflags 2.10.0", + "bitflags", "revm-bytecode 6.2.2", "revm-primitives 20.2.1", "serde", @@ -7912,7 +7533,7 @@ name = "revm-state" version = "8.0.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ - "bitflags 2.10.0", + "bitflags", "revm-bytecode 7.0.1", "revm-primitives 21.0.1", "serde", @@ -7924,7 +7545,7 @@ version = "8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" dependencies = [ - "bitflags 2.10.0", + "bitflags", "revm-bytecode 7.1.1", "revm-primitives 21.0.2", "serde", @@ -8030,35 +7651,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" -[[package]] -name = "rustacuda" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47208516ab5338b592d63560e90eaef405d0ec880347eaf7742d893b0a31e228" -dependencies = [ - "bitflags 1.3.2", - "cuda-driver-sys", - "rustacuda_core", - "rustacuda_derive", -] - -[[package]] -name = "rustacuda_core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3858b08976dc2f860c5efbbb48cdcb0d4fafca92a6ac0898465af16c0dbe848" - -[[package]] -name = "rustacuda_derive" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce8670a1a1d0fc2514a3b846dacdb65646f9bd494b6674cfacbb4ce430bd7e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rustc-demangle" version = "0.1.26" @@ -8107,7 +7699,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -8228,13 +7820,13 @@ version = "2.0.0" source = "git+https://github.com/scroll-tech/stateless-block-verifier?tag=scroll-v91.2#3a32848c9438432125751eae8837757f6b87562e" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-network", "alloy-primitives", "alloy-rpc-types-debug", "alloy-rpc-types-eth", - "alloy-serde 1.1.1", + "alloy-serde", "reth-chainspec", "reth-ethereum-forks", "reth-evm", @@ -8329,10 +7921,10 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.1.1", + "alloy-serde", "derive_more 2.0.1", "reth-codecs", "serde", @@ -8345,7 +7937,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-evm", "alloy-primitives", "auto_impl", @@ -8388,11 +7980,11 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.1.1", + "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.1.1", + "alloy-serde", "derive_more 2.0.1", "scroll-alloy-consensus", "serde", @@ -8436,7 +8028,7 @@ dependencies = [ "openvm-verify-stark-circuit", "scroll-zkvm-types", "serde_json", - "snark-verifier-sdk 0.2.1", + "snark-verifier-sdk", "toml", ] @@ -8515,7 +8107,7 @@ dependencies = [ "scroll-zkvm-verifier", "serde", "serde_json", - "snark-verifier-sdk 0.2.1", + "snark-verifier-sdk", "sysinfo", "tokio", "toml", @@ -8536,6 +8128,7 @@ dependencies = [ "git-version", "hex", "openvm-circuit", + "openvm-continuations", "openvm-cuda-backend", "openvm-deferral-circuit", "openvm-sdk", @@ -8576,7 +8169,7 @@ dependencies = [ "scroll-zkvm-types-chunk", "serde", "serde_json", - "snark-verifier-sdk 0.2.1", + "snark-verifier-sdk", ] [[package]] @@ -8584,7 +8177,7 @@ name = "scroll-zkvm-types-base" version = "0.8.0" dependencies = [ "alloy-primitives", - "alloy-serde 1.1.1", + "alloy-serde", "serde", "sha2 0.10.9", "sha3", @@ -8596,7 +8189,7 @@ version = "0.8.0" dependencies = [ "alloy-primitives", "c-kzg", - "halo2curves-axiom 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "itertools 0.14.0", "openvm", "openvm-algebra-guest", @@ -8678,7 +8271,7 @@ dependencies = [ "serde", "serde_json", "sha256", - "snark-verifier-sdk 0.2.1", + "snark-verifier-sdk", "tracing", ] @@ -8744,7 +8337,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -8931,7 +8524,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.4", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -8943,7 +8536,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -8978,7 +8571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", - "cfg-if 1.0.4", + "cfg-if", ] [[package]] @@ -9048,35 +8641,13 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" -[[package]] -name = "snark-verifier" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d798d8ce8e29b8820ecc1028ac44cc4fc0f0296728af6fe6a0c4db05782c0a4" -dependencies = [ - "halo2-base 0.5.0", - "halo2-ecc 0.5.0", - "hex", - "itertools 0.11.0", - "lazy_static", - "num-bigint", - "num-integer", - "num-traits", - "pairing 0.23.0", - "rand 0.8.6", - "revm 22.0.1", - "ruint", - "serde", - "sha3", -] - [[package]] name = "snark-verifier" version = "0.2.4" source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.4#c45e7d357b93d7b040d9e71d2787ba8fa3da2802" dependencies = [ - "halo2-base 0.5.2", - "halo2-ecc 0.5.2", + "halo2-base", + "halo2-ecc", "hex", "itertools 0.11.0", "lazy_static", @@ -9091,39 +8662,16 @@ dependencies = [ "sha3", ] -[[package]] -name = "snark-verifier-sdk" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338d065044702bf751e87cf353daac63e2fc4c53a3e323cbcd98c603ee6e66c" -dependencies = [ - "ark-std 0.3.0", - "bincode 1.3.3", - "ethereum-types", - "getset", - "halo2-base 0.5.0", - "hex", - "itertools 0.11.0", - "lazy_static", - "num-bigint", - "num-integer", - "num-traits", - "rand 0.8.6", - "rand_chacha 0.3.1", - "serde", - "serde_json", - "snark-verifier 0.2.1", -] - [[package]] name = "snark-verifier-sdk" version = "0.2.4" source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.4#c45e7d357b93d7b040d9e71d2787ba8fa3da2802" dependencies = [ + "ark-std 0.3.0", "bincode 1.3.3", "ethereum-types", "getset", - "halo2-base 0.5.2", + "halo2-base", "hex", "itertools 0.11.0", "lazy_static", @@ -9134,7 +8682,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_json", - "snark-verifier 0.2.4", + "snark-verifier", ] [[package]] @@ -9152,9 +8700,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spin" @@ -9197,7 +8742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" dependencies = [ "cc", - "cfg-if 1.0.4", + "cfg-if", "libc", "psm", "windows-sys 0.59.0", @@ -9396,15 +8941,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "test-case" version = "3.3.1" @@ -9420,7 +8956,7 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "proc-macro2", "quote", "syn 2.0.110", @@ -9484,7 +9020,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", ] [[package]] @@ -9712,7 +9248,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "futures-util", "http", @@ -10037,7 +9573,7 @@ version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -10050,7 +9586,7 @@ version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "js-sys", "once_cell", "wasm-bindgen", @@ -10139,15 +9675,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -10466,16 +9993,6 @@ dependencies = [ "tap", ] -[[package]] -name = "yastl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" -dependencies = [ - "flume", - "scopeguard", -] - [[package]] name = "yoke" version = "0.8.1" @@ -10604,7 +10121,7 @@ dependencies = [ "blake2", "bls12_381", "byteorder", - "cfg-if 1.0.4", + "cfg-if", "group 0.12.1", "group 0.13.0", "halo2", diff --git a/Cargo.toml b/Cargo.toml index a08c331c..46e7fbb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,7 +106,7 @@ ecies = { git = "https://github.com/scroll-tech/ecies-rs" } eyre = "0.6" color-eyre = "0.6" futures = "0.3" -halo2curves-axiom = { version = "0.7.2" } +halo2curves-axiom = { git = "https://github.com/axiom-crypto/halo2curves.git", tag = "v0.7.2" } itertools = "0.14" hex-literal = { version = "0.4.1", default-features = false } hex = "0.4" @@ -119,7 +119,7 @@ serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1.0" } serde_with = "3.11.0" base64 = "0.22" -snark-verifier-sdk = { version = "=0.2.1", default-features = false, features = [ +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.2.4", default-features = false, features = [ "loader_halo2", "halo2-axiom", "display", @@ -175,3 +175,14 @@ strip = false [profile.bench] inherits = "profiling" + +# Patch openvm-static-verifier so its `cuda` feature does not forward +# `snark-verifier-sdk/cuda`. This keeps OpenVM STARK proving on GPU while +# forcing the final Halo2 SNARK step onto CPU (the GPU prover fails with +# `cudaErrorInvalidConfiguration` on this machine). +# +# Also patch openvm-sdk so the EVM verifier template receives the public-values +# length in bytes (rv64 cells are 2 bytes), not in cell count. +[patch."https://github.com/openvm-org/openvm.git"] +openvm-static-verifier = { path = "patches/openvm-static-verifier" } +openvm-sdk = { path = "patches/openvm-sdk" } diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 4de73611..527f9a27 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [50420542, 1392989157, 448926711, 1020586158, 1753185748, 978552653, 1987597656, 1535570790]; +pub const COMMIT: [u32; 8] = [596660738, 356329379, 145996804, 1214471003, 1352764524, 1227343966, 253112671, 450394351]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 90402c8d..f8761582 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [786832452, 1653477522, 1394183768, 510849076, 34752204, 963795907, 1822012470, 1297862894]; +pub const COMMIT: [u32; 8] = [1434838598, 388554952, 1773275244, 1370434121, 1772714353, 1910323269, 288505202, 1962377575]; diff --git a/crates/circuits/batch-circuit/openvm.toml b/crates/circuits/batch-circuit/openvm.toml index a309c5b2..bfb51ff7 100644 --- a/crates/circuits/batch-circuit/openvm.toml +++ b/crates/circuits/batch-circuit/openvm.toml @@ -5,9 +5,9 @@ num_queries = 100 commit_proof_of_work_bits = 16 query_proof_of_work_bits = 16 -[app_vm_config.rv32i] +[app_vm_config.rv64i] -[app_vm_config.rv32m] +[app_vm_config.rv64m] [app_vm_config.io] diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 1c18528d..14b95eb9 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [2001906000, 1504752506, 1175753514, 1631401950, 1839606225, 783683098, 1568962809, 1700031006]; +pub const COMMIT: [u32; 8] = [1765220335, 887555519, 1633753004, 672640361, 859592620, 90340550, 1157473523, 1820772605]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index fd07c014..f48477fd 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [96506945, 1189901216, 890045270, 1752802540, 1058621785, 813050117, 204020090, 49333955]; +pub const COMMIT: [u32; 8] = [1358160996, 1327332497, 659543836, 1119784134, 1350569678, 589474776, 315507167, 477326715]; diff --git a/crates/circuits/bundle-circuit/openvm.toml b/crates/circuits/bundle-circuit/openvm.toml index a727c8fc..277ae5f1 100644 --- a/crates/circuits/bundle-circuit/openvm.toml +++ b/crates/circuits/bundle-circuit/openvm.toml @@ -5,9 +5,9 @@ num_queries = 100 commit_proof_of_work_bits = 16 query_proof_of_work_bits = 16 -[app_vm_config.rv32i] +[app_vm_config.rv64i] -[app_vm_config.rv32m] +[app_vm_config.rv64m] [app_vm_config.io] diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 48c79073..6bc6baab 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1531285366, 538142123, 1569134888, 1545025877, 1752434853, 561247774, 1106370680, 686967467]; +pub const COMMIT: [u32; 8] = [585943433, 392262880, 782550780, 736181627, 154452102, 790846675, 713202392, 989649511]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index cfa3b260..255c054c 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1452956221, 435253581, 1946192292, 1141638848, 1783296127, 34745095, 1581934565, 1871321183]; +pub const COMMIT: [u32; 8] = [716929330, 1753253055, 1218060174, 1856652980, 1340168684, 1535644868, 523453420, 65380119]; diff --git a/crates/circuits/chunk-circuit/openvm.toml b/crates/circuits/chunk-circuit/openvm.toml index 9ddc457b..896f4bfc 100644 --- a/crates/circuits/chunk-circuit/openvm.toml +++ b/crates/circuits/chunk-circuit/openvm.toml @@ -5,13 +5,13 @@ num_queries = 100 commit_proof_of_work_bits = 16 query_proof_of_work_bits = 16 -[app_vm_config.rv32i] +[app_vm_config.rv64i] [app_vm_config.io] [app_vm_config.keccak] -[app_vm_config.rv32m] +[app_vm_config.rv64m] range_tuple_checker_sizes = [256, 8192] [app_vm_config.bigint] diff --git a/crates/prover/Cargo.toml b/crates/prover/Cargo.toml index d1dd4f4c..2b9a62e6 100644 --- a/crates/prover/Cargo.toml +++ b/crates/prover/Cargo.toml @@ -12,6 +12,7 @@ scroll-zkvm-verifier.workspace = true bincode_v1.workspace = true tracing.workspace = true openvm-circuit = { workspace = true } +openvm-continuations = { workspace = true } openvm-sdk = { workspace = true } openvm-sdk-config = { workspace = true } openvm-static-verifier = { workspace = true } @@ -37,6 +38,10 @@ cudarc = { version = "0.9", optional = true } [features] default = [] -cuda = ["openvm-sdk/cuda", "dep:cudarc", "openvm-verify-stark-circuit/cuda", "dep:openvm-cuda-backend"] +cuda = [ + "dep:cudarc", + "dep:openvm-cuda-backend", + "openvm-sdk/cuda", +] diff --git a/crates/types/batch/Cargo.toml b/crates/types/batch/Cargo.toml index e2836f22..6044a9b4 100644 --- a/crates/types/batch/Cargo.toml +++ b/crates/types/batch/Cargo.toml @@ -20,7 +20,7 @@ openvm-ecc-guest = { workspace = true, features = ["halo2curves"] } openvm-pairing-guest = { workspace = true, features = ["halo2curves"] } openvm-pairing = { workspace = true, features = ["bls12_381", "halo2curves"] } openvm-sha2.workspace = true -halo2curves-axiom = "0.7.0" +halo2curves-axiom.workspace = true sbv-primitives = { workspace = true, optional = true } c-kzg = { workspace = true, optional = true } diff --git a/crates/types/chunk/src/scroll/execute.rs b/crates/types/chunk/src/scroll/execute.rs index 512bf82e..d0127215 100644 --- a/crates/types/chunk/src/scroll/execute.rs +++ b/crates/types/chunk/src/scroll/execute.rs @@ -84,7 +84,7 @@ pub fn execute(witness: ChunkWitness) -> Result { }), }; - #[cfg(target_os = "zkvm")] + #[cfg(target_os = "openvm")] println!("chunk_info = {}", chunk_info); Ok(chunk_info) diff --git a/crates/types/circuit/src/lib.rs b/crates/types/circuit/src/lib.rs index a3d033eb..3d1e9238 100644 --- a/crates/types/circuit/src/lib.rs +++ b/crates/types/circuit/src/lib.rs @@ -60,7 +60,7 @@ where fn verify_proofs(witness: &Self::Witness) -> Vec { let proofs = witness.get_proofs(); - #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] + #[cfg(all(target_os = "openvm", target_arch = "riscv64"))] { let input_commits: Vec<[u8; 32]> = openvm::io::read(); assert_eq!( @@ -75,7 +75,7 @@ where } } - #[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] + #[cfg(not(all(target_os = "openvm", target_arch = "riscv64")))] { for proof in proofs.iter() { Self::verify_commitments(&proof.commitment); @@ -127,7 +127,7 @@ fn u32_array_to_commit(arr: &[u32; 8]) -> [u8; 32] { } /// Verify a root proof using deferred STARK verification (v2). -#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] +#[cfg(all(target_os = "openvm", target_arch = "riscv64"))] fn verify_proof(commitment: &ProgramCommitment, public_inputs: &[u32], input_commit: &[u8; 32]) { use openvm_verify_stark_guest::{verify_stark, ProofOutput}; @@ -137,15 +137,22 @@ fn verify_proof(commitment: &ProgramCommitment, public_inputs: &[u32], input_com let expected = ProofOutput { app_exe_commit: u32_array_to_commit(&commitment.exe), app_vm_commit: u32_array_to_commit(&commitment.vm), - user_public_values: public_inputs.iter().flat_map(|&w| w.to_le_bytes()).collect(), + // OpenVM v2 rv64 stores user public values as 2-byte (u16) cells. A 32-byte pi_hash is + // represented by 16 little-endian u16 cells followed by 16 zero cells, so the collapsed + // byte layout is `[pi_hash bytes][32 zero bytes]`. + user_public_values: { + let mut pvs: Vec = public_inputs.iter().map(|&w| w as u8).collect(); + pvs.resize(pvs.len() * 2, 0); + pvs + }, }; verify_stark::<0>(input_commit, &expected); } -#[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] +#[cfg(not(all(target_os = "openvm", target_arch = "riscv64")))] fn verify_proof(_commitment: &ProgramCommitment, _public_inputs: &[u32], _input_commit: &[u8; 32]) { - panic!("verify_proof should only be called on zkvm target"); + panic!("verify_proof should only be called on openvm target"); } /// This macro is used to manually drop an expression on zkvm (non x86/aarch64 targets). diff --git a/crates/verifier/src/verifier.rs b/crates/verifier/src/verifier.rs index 53a46015..3c928e5f 100644 --- a/crates/verifier/src/verifier.rs +++ b/crates/verifier/src/verifier.rs @@ -149,7 +149,10 @@ mod tests { /// test method to be compatible with euclid wrapped proofs pub fn verify_wrapped_proof(&self, proof: &WrappedProof) -> eyre::Result<()> { match &proof.proof { - ProofEnum::Evm(p) => self.verify_evm_proof(&p.clone().into(), &proof.vk), + ProofEnum::Evm(p) => { + let _ = self.verify_evm_proof(&p.clone().into(), &proof.vk)?; + Ok(()) + } ProofEnum::Stark(p) => self.verify_stark_proof(p, &proof.vk), } } diff --git a/patches/openvm-sdk/Cargo.toml b/patches/openvm-sdk/Cargo.toml new file mode 100644 index 00000000..84f73fce --- /dev/null +++ b/patches/openvm-sdk/Cargo.toml @@ -0,0 +1,136 @@ +[package] +name = "openvm-sdk" +version = "2.0.0-beta.2" +edition = "2021" +rust-version = "1.91.1" +authors = ["OpenVM Authors"] +homepage = "https://openvm.dev" +repository = "https://github.com/openvm-org/" +license = "MIT OR Apache-2.0" +autoexamples = false + +[dependencies] +openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, features = ["cpu-backend"] } +openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, optional = true } + +openvm-build = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } + +openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +# Point to the local patch so `openvm-static-verifier/cuda` does not enable +# `snark-verifier-sdk/cuda` (Halo2 SNARK stays on CPU). +openvm-static-verifier = { path = "../openvm-static-verifier", default-features = false, optional = true } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.5.2", default-features = false, optional = true, features = ["halo2-axiom"] } + +alloy-sol-types = { version = "1.4.1", optional = true } +forge-fmt = { git = "https://github.com/foundry-rs/foundry.git", tag = "v1.5.0", optional = true } +tempfile = { version = "3.13.0", optional = true } + +bitcode = { version = "0.6.5", default-features = false, features = ["serde"] } +cfg-if = "1.0.0" +clap = { version = "4.5.23", features = ["derive"] } +derivative = "2.2.0" +derive_more = { version = "1.0.0", features = ["display"], default-features = false } +derive-new = "0.6.0" +eyre = "0.6.12" +getset = "0.1.3" +hex = { version = "0.4.3", default-features = false } +itertools = { version = "0.14.0", default-features = false } +serde = { version = "1.0.201", default-features = false, features = ["derive"] } +serde_json = "1.0.117" +serde_with = { version = "3.11.0", features = ["hex"] } +thiserror = "1.0.65" +tracing = "0.1.40" +metrics = { version = "0.23.0", optional = true } + +[dev-dependencies] +tempfile = "3.13.0" + +[features] +default = ["parallel", "jemalloc"] +root-prover = [ + "openvm-continuations/root-prover", + "openvm-stark-sdk/baby-bear-bn254-poseidon2", + "openvm-cuda-backend?/baby-bear-bn254-poseidon2", +] +evm-prove = [ + "root-prover", + "dep:openvm-static-verifier", + "dep:halo2-base", + "openvm-static-verifier/evm-prove", +] +evm-verify = [ + "evm-prove", + "openvm-static-verifier/evm-verify", + "dep:alloy-sol-types", + "dep:tempfile", +] +# Optional Solidity code formatting; requires Rust 1.91+ due to foundry/alloy transitive deps. +evm-verify-fmt = [ + "evm-verify", + "dep:forge-fmt", +] +metrics = ["dep:metrics", "openvm-continuations/metrics", "openvm-sdk-config/metrics"] +aot = [ + "openvm-circuit/aot", + "openvm-sdk-config/aot", +] +rvr = [ + "openvm-circuit/rvr", + "openvm-sdk-config/rvr", +] +tco = [ + "openvm-circuit/tco", + "openvm-sdk-config/tco", +] +unprotected = ["openvm-circuit/unprotected"] + +# for guest profiling: +perf-metrics = [ + "openvm-circuit/perf-metrics", + "openvm-transpiler/function-span", + "openvm-sdk-config/perf-metrics" +] + +# turns on stark-backend debugger in all proofs +stark-debug = ["openvm-circuit/stark-debug"] +test-utils = ["openvm-circuit/test-utils"] + +parallel = ["openvm-continuations/parallel", "openvm-sdk-config/parallel"] +mimalloc = ["openvm-circuit/mimalloc", "openvm-sdk-config/mimalloc"] +jemalloc = ["openvm-circuit/jemalloc", "openvm-sdk-config/jemalloc"] +jemalloc-prof = ["openvm-circuit/jemalloc-prof"] + +cuda = [ + "dep:openvm-cuda-backend", + "openvm-circuit/cuda", + "openvm-sdk-config/cuda", + "openvm-continuations/cuda", + "openvm-verify-stark-circuit/cuda", + "openvm-static-verifier?/cuda", +] +cell-profiling = [ + "evm-prove", + "openvm-static-verifier/cell-profiling", +] + +[[example]] +name = "sdk_app" +path = "examples/sdk_app.rs" + +[[example]] +name = "sdk_stark" +path = "examples/sdk_stark.rs" + +[[example]] +name = "sdk_evm" +path = "examples/sdk_evm.rs" +required-features = ["evm-verify"] diff --git a/patches/openvm-sdk/contracts/.gitignore b/patches/openvm-sdk/contracts/.gitignore new file mode 100644 index 00000000..85198aaa --- /dev/null +++ b/patches/openvm-sdk/contracts/.gitignore @@ -0,0 +1,14 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json b/patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json new file mode 100644 index 00000000..7ee1df76 --- /dev/null +++ b/patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json @@ -0,0 +1,30 @@ +[ + { + "type": "function", + "name": "verify", + "inputs": [ + { + "name": "publicValues", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "proofData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appExeCommit", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "appVmCommit", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "view" + } +] \ No newline at end of file diff --git a/patches/openvm-sdk/contracts/foundry.toml b/patches/openvm-sdk/contracts/foundry.toml new file mode 100644 index 00000000..1e28834e --- /dev/null +++ b/patches/openvm-sdk/contracts/foundry.toml @@ -0,0 +1,31 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +verbosity = 2 +solc = "0.8.19" +optimizer = true +optimizer_runs = 100000 +evm_version = "shanghai" +show_progress = true +fs_permissions = [{ access = "read", path = "./template"}, { access = "read", path = "./test/helpers/MockDeps.sol"}] +ffi = true + +[profile.default.optimizer_details] + constantOptimizer = false + yul = false + +[fuzz] + runs = 256 + +[fmt] + bracket_spacing = true + int_types = "long" + line_length = 120 + multiline_func_header = "attributes_first" + number_underscore = "thousands" + quote_style = "double" + single_line_statement_blocks = "single" + tab_width = 4 + wrap_comments = false + \ No newline at end of file diff --git a/patches/openvm-sdk/contracts/lib/.gitignore b/patches/openvm-sdk/contracts/lib/.gitignore new file mode 100644 index 00000000..03cabd3d --- /dev/null +++ b/patches/openvm-sdk/contracts/lib/.gitignore @@ -0,0 +1 @@ +forge-std/ diff --git a/patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol b/patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol new file mode 100644 index 00000000..ac8292cd --- /dev/null +++ b/patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IOpenVmHalo2Verifier { + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + external + view; +} diff --git a/patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol b/patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol new file mode 100644 index 00000000..8f6f2b57 --- /dev/null +++ b/patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import { Halo2Verifier } from "./Halo2Verifier.sol"; +import { IOpenVmHalo2Verifier } from "./interfaces/IOpenVmHalo2Verifier.sol"; + +type MemoryPointer is uint256; + +/// @notice This contract provides a thin wrapper around the Halo2 verifier +/// outputted by `snark-verifier`, exposing a more user-friendly interface. +contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { + /// @dev Invalid public values length + error InvalidPublicValuesLength(uint256 expected, uint256 actual); + + /// @dev Invalid proof data length + error InvalidProofDataLength(uint256 expected, uint256 actual); + + /// @dev Proof verification failed + error ProofVerificationFailed(); + + /// @dev The length of the proof data, in bytes. + uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32; + + /// @dev The number of public value limbs exposed by the Halo2 circuit. + /// This value is set by OpenVM and is guaranteed to be no larger than 8192. + uint256 private constant PUBLIC_VALUES_LENGTH = {PUBLIC_VALUES_LENGTH}; + + /// @dev The byte width of each public value limb (1 for rv32, 2 for rv64). + uint256 private constant PUBLIC_VALUES_LIMB_SIZE = {PUBLIC_VALUES_LIMB_SIZE}; + + /// @dev The total byte length of the public values payload. + uint256 private constant PUBLIC_VALUES_BYTE_LENGTH = PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE; + + /// @dev The length of the full proof, in bytes + uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32; + + /// @dev The version of OpenVM that generated this verifier. + string public constant OPENVM_VERSION = "{OPENVM_VERSION}"; + + /// @notice A wrapper that constructs the proof into the right format for + /// use with the `snark-verifier` verification. + /// + /// @dev The verifier expected proof format is: + /// proof[..12 * 32]: KZG accumulator + /// proof[12 * 32..13 * 32]: app exe commit + /// proof[13 * 32..14 * 32]: app vm commit + /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] + /// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix + /// + /// @param publicValues The PVs revealed by the OpenVM guest program. Each + /// public-value limb occupies PUBLIC_VALUES_LIMB_SIZE bytes in little-endian. + /// @param proofData All components of the proof except the public values and + /// app exe and vm commits. The expected format is: + /// `abi.encodePacked(kzgAccumulator, proofSuffix)` + /// @param appExeCommit The commitment to the OpenVM application executable whose execution + /// is being verified. + /// @param appVmCommit The commitment to the VM configuration. + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { + if (publicValues.length != PUBLIC_VALUES_BYTE_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_BYTE_LENGTH, publicValues.length); + if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length); + + // We will format the public values and construct the full proof payload + // below. + + MemoryPointer proofPtr = _constructProof(publicValues, proofData, appExeCommit, appVmCommit); + + uint256 fullProofLength = FULL_PROOF_LENGTH; + + /// @solidity memory-safe-assembly + assembly { + // Self-call using the proof as calldata + if iszero(staticcall(gas(), address(), proofPtr, fullProofLength, 0, 0)) { + mstore(0x00, 0xd611c318) // ProofVerificationFailed() + revert(0x1c, 0x04) + } + } + } + + /// @dev The assembly code should perform the same function as the following + /// solidity code: + // + /// ```solidity + /// bytes memory proof = + /// abi.encodePacked(proofData[0:0x180], appExeCommit, appVmCommit, publicValuesPayload, proofData[0x180:]); + /// ``` + // + /// where `publicValuesPayload` is a memory payload with each byte in + /// `publicValues` separated into its own `bytes32` word. + /// + /// This function does not clean the memory it allocates. Since it is the + /// only memory write that occurs in the call frame, we know that + /// the memory region cannot have been dirtied. + /// + /// @return proofPtr Memory pointer to the beginning of the constructed + /// proof. This pointer does not follow `bytes memory` semantics. + function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + internal + pure + returns (MemoryPointer proofPtr) + { + uint256 fullProofLength = FULL_PROOF_LENGTH; + + // The expected proof format using hex offsets: + // + // proof[..0x180]: KZG accumulator + // proof[0x180..0x1a0]: app exe commit + // proof[0x1a0..0x1c0]: app vm commit + // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] + // proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix + + /// @solidity memory-safe-assembly + assembly { + proofPtr := mload(0x40) + // Allocate the memory as a safety measure. + mstore(0x40, add(proofPtr, fullProofLength)) + + // Copy the KZG accumulator (length 0x180) into the beginning of + // the memory buffer + calldatacopy(proofPtr, proofData.offset, 0x180) + + // Copy the App Exe Commit and App Vm Commit into the memory buffer + mstore(add(proofPtr, 0x180), appExeCommit) + mstore(add(proofPtr, 0x1a0), appVmCommit) + + // Copy the Proof Suffix (length 43 * 32 = 0x560) into the + // end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in + // between for the publicValuesPayload. + // + // Begin copying from the end of the KZG accumulator in the + // calldata buffer (0x180) + let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) + calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) + + // Copy each public-value limb into the low bytes of the corresponding + // Fr slot. user_public_values stores limbs in little-endian, but each + // 32-byte word is interpreted by the EVM as big-endian, so we reverse + // the limb bytes as we copy them to the end of the word. + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + let wordPtr := add(proofPtr, add(0x1c0, shl(5, i))) + // Clear the full word first; only the low bytes are overwritten. + mstore(wordPtr, 0) + for { let j := 0 } iszero(eq(j, PUBLIC_VALUES_LIMB_SIZE)) { j := add(j, 1) } { + // publicValues[i*LIMB_SIZE + j] is copied to the j-th byte + // from the end of the word, i.e. wordPtr + (0x1f - j). + calldatacopy( + add(wordPtr, sub(0x1f, j)), + add(publicValues.offset, add(mul(i, PUBLIC_VALUES_LIMB_SIZE), j)), + 0x01 + ) + } + } + } + } +} diff --git a/patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol b/patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol new file mode 100644 index 00000000..2547ba18 --- /dev/null +++ b/patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import { LibString } from "./helpers/LibString.sol"; +import { Test, console2, safeconsole as console } from "forge-std/Test.sol"; +import { IOpenVmHalo2Verifier } from "../src/IOpenVmHalo2Verifier.sol"; + +contract TemplateTest is Test { + bytes proofData; + bytes32 appExeCommit = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + bytes32 appVmCommit = 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE; + bytes guestPvs; + + uint256 publicValuesLength; + uint256 fullProofWords; + uint256 fullProofLength; + + string _code = vm.readFile("template/OpenVmHalo2Verifier.sol"); + string deps = vm.readFile("test/helpers/MockDeps.sol"); + + function setUp() public { + proofData = new bytes(55 * 32); + for (uint256 i = 0; i < 55; i++) { + for (uint256 j = 0; j < 32; j++) { + proofData[i * 32 + j] = bytes1(uint8(i)); + } + } + } + + /// forge-config: default.fuzz.runs = 10 + function testFuzz_ProofFormat(uint256 _publicValuesLength) public { + publicValuesLength = bound(_publicValuesLength, 1, 10_000); + publicValuesLength = 8; + fullProofWords = (12 + 2 + publicValuesLength + 43); + fullProofLength = fullProofWords * 32; + + guestPvs = new bytes(publicValuesLength); + for (uint256 i = 0; i < publicValuesLength; i++) { + guestPvs[i] = bytes1(uint8(i)); + } + + IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); + + (bool success,) = address(verifier).delegatecall( + abi.encodeCall(IOpenVmHalo2Verifier.verify, (guestPvs, proofData, appExeCommit, appVmCommit)) + ); + require(success, "Verification failed"); + } + + fallback(bytes calldata proof) external returns (bytes memory) { + bytes memory proofDataExpected = proofData; + + uint256 proofSuffixOffset = 0x1c0 + (32 * publicValuesLength); + + bytes memory kzgAccumulator = proof[0:0x180]; + bytes memory proofSuffix = proof[proofSuffixOffset:]; + bytes memory _proofData = abi.encodePacked(kzgAccumulator, proofSuffix); + + require(keccak256(_proofData) == keccak256(proofDataExpected), "Partial proof mismatch"); + + bytes memory _appExeCommit = proof[0x180:0x1a0]; + bytes memory _appVmCommit = proof[0x1a0:0x1c0]; + + require(bytes32(_appExeCommit) == appExeCommit, "App exe commit mismatch"); + require(bytes32(_appVmCommit) == appVmCommit, "App vm commit mismatch"); + + bytes calldata _guestPvs = proof[0x1c0:0x1c0 + 32 * publicValuesLength]; + for (uint256 i = 0; i < publicValuesLength; ++i) { + uint256 expected = uint256(uint8(guestPvs[i])); + uint256 actual = uint256(bytes32(_guestPvs[i * 32:(i + 1) * 32])); + require(expected == actual, "Guest PVs hash mismatch"); + } + + // Suppress return value warning + assembly { + return(0x00, 0x00) + } + } + + function test_RevertWhen_InvalidPublicValuesLength() public { + publicValuesLength = 32; + IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); + + bytes memory invalidPvs = new bytes(0); + bytes4 sig = bytes4(keccak256("InvalidPublicValuesLength(uint256,uint256)")); + + vm.expectRevert(abi.encodeWithSelector(sig, 32, invalidPvs.length)); + verifier.verify(invalidPvs, hex"", bytes32(0), bytes32(0)); + } + + function test_RevertWhen_InvalidProofDataLength() public { + publicValuesLength = 32; + IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); + + bytes memory invalidProofData = new bytes(0); + bytes4 sig = bytes4(keccak256("InvalidProofDataLength(uint256,uint256)")); + + bytes memory pvs = new bytes(publicValuesLength); + + vm.expectRevert(abi.encodeWithSelector(sig, 55 * 32, invalidProofData.length)); + verifier.verify(pvs, invalidProofData, appExeCommit, appVmCommit); + } + + function test_RevertWhen_ProofVerificationFailed() public { + publicValuesLength = 32; + IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); + + bytes memory _proofData = new bytes(55 * 32); + bytes memory pvs = new bytes(publicValuesLength); + + bytes4 sig = bytes4(keccak256("ProofVerificationFailed()")); + + vm.expectRevert(abi.encodeWithSelector(sig)); + verifier.verify(pvs, _proofData, appExeCommit, appVmCommit); + } + + function _compileAndDeployOpenVmVerifier(uint256 _publicValuesLength) + private + returns (IOpenVmHalo2Verifier verifier) + { + string memory code = LibString.replace(_code, "{PUBLIC_VALUES_LENGTH}", LibString.toString(_publicValuesLength)); + + // `code` will look like this: + // + // // SPDX-License-Identifier: MIT + // pragma solidity 0.8.19; + // + // import { Halo2Verifier } ... + // import { IOpenVmHalo2Verifier } ... + // + // contract OpenVmHalo2Verifier { .. } + // + // We want to replace the `import` statements with inlined deps for JIT + // compilation. + string memory inlinedCode = LibString.replace( + code, + "import { Halo2Verifier } from \"./Halo2Verifier.sol\";\nimport { IOpenVmHalo2Verifier } from \"./interfaces/IOpenVmHalo2Verifier.sol\";", + deps + ); + + // Must use solc 0.8.19 + string[] memory commands = new string[](3); + commands[0] = "sh"; + commands[1] = "-c"; + commands[2] = string.concat( + "echo ", + "'", + inlinedCode, + "'", + " | solc --no-optimize-yul --bin --optimize --optimize-runs 100000 - ", + " | awk 'BEGIN{found=0} /:OpenVmHalo2Verifier/ {found=1; next} found && /^Binary:/ {getline; print; exit}'" + ); + + bytes memory compiledVerifier = vm.ffi(commands); + + assembly { + verifier := create(0, add(compiledVerifier, 0x20), mload(compiledVerifier)) + if iszero(extcodesize(verifier)) { revert(0, 0) } + } + } +} diff --git a/patches/openvm-sdk/contracts/test/helpers/LibString.sol b/patches/openvm-sdk/contracts/test/helpers/LibString.sol new file mode 100644 index 00000000..f046fa40 --- /dev/null +++ b/patches/openvm-sdk/contracts/test/helpers/LibString.sol @@ -0,0 +1,1628 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +/// @notice Library for byte related operations. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol) +library LibBytes { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRUCTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Goated bytes storage struct that totally MOGs, no cap, fr. + /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af. + /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. + struct BytesStorage { + bytes32 _spacer; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The constant returned when the `search` is not found in the bytes. + uint256 internal constant NOT_FOUND = type(uint256).max; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTE STORAGE OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Sets the value of the bytes storage `$` to `s`. + function set(BytesStorage storage $, bytes memory s) internal { + /// @solidity memory-safe-assembly + assembly { + let n := mload(s) + let packed := or(0xff, shl(8, n)) + for { let i := 0 } 1 { } { + if iszero(gt(n, 0xfe)) { + i := 0x1f + packed := or(n, shl(8, mload(add(s, i)))) + if iszero(gt(n, i)) { break } + } + let o := add(s, 0x20) + mstore(0x00, $.slot) + for { let p := keccak256(0x00, 0x20) } 1 { } { + sstore(add(p, shr(5, i)), mload(add(o, i))) + i := add(i, 0x20) + if iszero(lt(i, n)) { break } + } + break + } + sstore($.slot, packed) + } + } + + /// @dev Sets the value of the bytes storage `$` to `s`. + function setCalldata(BytesStorage storage $, bytes calldata s) internal { + /// @solidity memory-safe-assembly + assembly { + let packed := or(0xff, shl(8, s.length)) + for { let i := 0 } 1 { } { + if iszero(gt(s.length, 0xfe)) { + i := 0x1f + packed := or(s.length, shl(8, shr(8, calldataload(s.offset)))) + if iszero(gt(s.length, i)) { break } + } + mstore(0x00, $.slot) + for { let p := keccak256(0x00, 0x20) } 1 { } { + sstore(add(p, shr(5, i)), calldataload(add(s.offset, i))) + i := add(i, 0x20) + if iszero(lt(i, s.length)) { break } + } + break + } + sstore($.slot, packed) + } + } + + /// @dev Sets the value of the bytes storage `$` to the empty bytes. + function clear(BytesStorage storage $) internal { + delete $._spacer; + } + + /// @dev Returns whether the value stored is `$` is the empty bytes "". + function isEmpty(BytesStorage storage $) internal view returns (bool) { + return uint256($._spacer) & 0xff == uint256(0); + } + + /// @dev Returns the length of the value stored in `$`. + function length(BytesStorage storage $) internal view returns (uint256 result) { + result = uint256($._spacer); + /// @solidity memory-safe-assembly + assembly { + let n := and(0xff, result) + result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n)))) + } + } + + /// @dev Returns the value stored in `$`. + function get(BytesStorage storage $) internal view returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let o := add(result, 0x20) + let packed := sload($.slot) + let n := shr(8, packed) + for { let i := 0 } 1 { } { + if iszero(eq(or(packed, 0xff), packed)) { + mstore(o, packed) + n := and(0xff, packed) + i := 0x1f + if iszero(gt(n, i)) { break } + } + mstore(0x00, $.slot) + for { let p := keccak256(0x00, 0x20) } 1 { } { + mstore(add(o, i), sload(add(p, shr(5, i)))) + i := add(i, 0x20) + if iszero(lt(i, n)) { break } + } + break + } + mstore(result, n) // Store the length of the memory. + mstore(add(o, n), 0) // Zeroize the slot after the bytes. + mstore(0x40, add(add(o, n), 0x20)) // Allocate memory. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTES OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. + function replace(bytes memory subject, bytes memory needle, bytes memory replacement) + internal + pure + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let needleLen := mload(needle) + let replacementLen := mload(replacement) + let d := sub(result, subject) // Memory difference. + let i := add(subject, 0x20) // Subject bytes pointer. + mstore(0x00, add(i, mload(subject))) // End of subject. + if iszero(gt(needleLen, mload(subject))) { + let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1) + let h := 0 // The hash of `needle`. + if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } + let s := mload(add(needle, 0x20)) + for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 { } { + let t := mload(i) + // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. + if iszero(shr(m, xor(t, s))) { + if h { + if iszero(eq(keccak256(i, needleLen), h)) { + mstore(add(i, d), t) + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + // Copy the `replacement` one word at a time. + for { let j := 0 } 1 { } { + mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) + j := add(j, 0x20) + if iszero(lt(j, replacementLen)) { break } + } + d := sub(add(d, replacementLen), needleLen) + if needleLen { + i := add(i, needleLen) + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + mstore(add(i, d), t) + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + } + } + let end := mload(0x00) + let n := add(sub(d, add(result, 0x20)), end) + // Copy the rest of the bytes one word at a time. + for { } lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } + let o := add(i, d) + mstore(o, 0) // Zeroize the slot after the bytes. + mstore(0x40, add(o, 0x20)) // Allocate memory. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from left to right, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function indexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + result := not(0) // Initialize to `NOT_FOUND`. + for { let subjectLen := mload(subject) } 1 { } { + if iszero(mload(needle)) { + result := from + if iszero(gt(from, subjectLen)) { break } + result := subjectLen + break + } + let needleLen := mload(needle) + let subjectStart := add(subject, 0x20) + + subject := add(subjectStart, from) + let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) + let m := shl(3, sub(0x20, and(needleLen, 0x1f))) + let s := mload(add(needle, 0x20)) + + if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } + + if iszero(lt(needleLen, 0x20)) { + for { let h := keccak256(add(needle, 0x20), needleLen) } 1 { } { + if iszero(shr(m, xor(mload(subject), s))) { + if eq(keccak256(subject, needleLen), h) { + result := sub(subject, subjectStart) + break + } + } + subject := add(subject, 1) + if iszero(lt(subject, end)) { break } + } + break + } + for { } 1 { } { + if iszero(shr(m, xor(mload(subject), s))) { + result := sub(subject, subjectStart) + break + } + subject := add(subject, 1) + if iszero(lt(subject, end)) { break } + } + break + } + } + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from left to right. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { + return indexOf(subject, needle, 0); + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from right to left, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from) + internal + pure + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + for { } 1 { } { + result := not(0) // Initialize to `NOT_FOUND`. + let needleLen := mload(needle) + if gt(needleLen, mload(subject)) { break } + let w := result + + let fromMax := sub(mload(subject), needleLen) + if iszero(gt(fromMax, from)) { from := fromMax } + + let end := add(add(subject, 0x20), w) + subject := add(add(subject, 0x20), from) + if iszero(gt(subject, end)) { break } + // As this function is not too often used, + // we shall simply use keccak256 for smaller bytecode size. + for { let h := keccak256(add(needle, 0x20), needleLen) } 1 { } { + if eq(keccak256(subject, needleLen), h) { + result := sub(subject, add(end, 1)) + break + } + subject := add(subject, w) // `sub(subject, 1)`. + if iszero(gt(subject, end)) { break } + } + break + } + } + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from right to left. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function lastIndexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { + return lastIndexOf(subject, needle, type(uint256).max); + } + + /// @dev Returns true if `needle` is found in `subject`, false otherwise. + function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) { + return indexOf(subject, needle) != NOT_FOUND; + } + + /// @dev Returns whether `subject` starts with `needle`. + function startsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + let n := mload(needle) + // Just using keccak256 directly is actually cheaper. + let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n)) + result := lt(gt(n, mload(subject)), t) + } + } + + /// @dev Returns whether `subject` ends with `needle`. + function endsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + let n := mload(needle) + let notInRange := gt(n, mload(subject)) + // `subject + 0x20 + max(subject.length - needle.length, 0)`. + let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n))) + // Just using keccak256 directly is actually cheaper. + result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange) + } + } + + /// @dev Returns `subject` repeated `times`. + function repeat(bytes memory subject, uint256 times) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + let l := mload(subject) // Subject length. + if iszero(or(iszero(times), iszero(l))) { + result := mload(0x40) + subject := add(subject, 0x20) + let o := add(result, 0x20) + for { } 1 { } { + // Copy the `subject` one word at a time. + for { let j := 0 } 1 { } { + mstore(add(o, j), mload(add(subject, j))) + j := add(j, 0x20) + if iszero(lt(j, l)) { break } + } + o := add(o, l) + times := sub(times, 1) + if iszero(times) { break } + } + mstore(o, 0) // Zeroize the slot after the bytes. + mstore(0x40, add(o, 0x20)) // Allocate memory. + mstore(result, sub(o, add(result, 0x20))) // Store the length. + } + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). + /// `start` and `end` are byte offsets. + function slice(bytes memory subject, uint256 start, uint256 end) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + let l := mload(subject) // Subject length. + if iszero(gt(l, end)) { end := l } + if iszero(gt(l, start)) { start := l } + if lt(start, end) { + result := mload(0x40) + let n := sub(end, start) + let i := add(subject, start) + let w := not(0x1f) + // Copy the `subject` one word at a time, backwards. + for { let j := and(add(n, 0x1f), w) } 1 { } { + mstore(add(result, j), mload(add(i, j))) + j := add(j, w) // `sub(j, 0x20)`. + if iszero(j) { break } + } + let o := add(add(result, 0x20), n) + mstore(o, 0) // Zeroize the slot after the bytes. + mstore(0x40, add(o, 0x20)) // Allocate memory. + mstore(result, n) // Store the length. + } + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. + /// `start` is a byte offset. + function slice(bytes memory subject, uint256 start) internal pure returns (bytes memory result) { + result = slice(subject, start, type(uint256).max); + } + + /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). + /// `start` and `end` are byte offsets. Faster than Solidity's native slicing. + function sliceCalldata(bytes calldata subject, uint256 start, uint256 end) + internal + pure + returns (bytes calldata result) + { + /// @solidity memory-safe-assembly + assembly { + end := xor(end, mul(xor(end, subject.length), lt(subject.length, end))) + start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) + result.offset := add(subject.offset, start) + result.length := mul(lt(start, end), sub(end, start)) + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. + /// `start` is a byte offset. Faster than Solidity's native slicing. + function sliceCalldata(bytes calldata subject, uint256 start) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) + result.offset := add(subject.offset, start) + result.length := mul(lt(start, subject.length), sub(subject.length, start)) + } + } + + /// @dev Reduces the size of `subject` to `n`. + /// If `n` is greater than the size of `subject`, this will be a no-op. + function truncate(bytes memory subject, uint256 n) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := subject + mstore(mul(lt(n, mload(result)), result), n) + } + } + + /// @dev Returns a copy of `subject`, with the length reduced to `n`. + /// If `n` is greater than the size of `subject`, this will be a no-op. + function truncatedCalldata(bytes calldata subject, uint256 n) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + result.offset := subject.offset + result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n))) + } + } + + /// @dev Returns all the indices of `needle` in `subject`. + /// The indices are byte offsets. + function indicesOf(bytes memory subject, bytes memory needle) internal pure returns (uint256[] memory result) { + /// @solidity memory-safe-assembly + assembly { + let searchLen := mload(needle) + if iszero(gt(searchLen, mload(subject))) { + result := mload(0x40) + let i := add(subject, 0x20) + let o := add(result, 0x20) + let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) + let h := 0 // The hash of `needle`. + if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } + let s := mload(add(needle, 0x20)) + for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 { } { + let t := mload(i) + // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. + if iszero(shr(m, xor(t, s))) { + if h { + if iszero(eq(keccak256(i, searchLen), h)) { + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. + o := add(o, 0x20) + i := add(i, searchLen) // Advance `i` by `searchLen`. + if searchLen { + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + } + mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. + // Allocate memory for result. + // We allocate one more word, so this array can be recycled for {split}. + mstore(0x40, add(o, 0x20)) + } + } + } + + /// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes. + function split(bytes memory subject, bytes memory delimiter) internal pure returns (bytes[] memory result) { + uint256[] memory indices = indicesOf(subject, delimiter); + /// @solidity memory-safe-assembly + assembly { + let w := not(0x1f) + let indexPtr := add(indices, 0x20) + let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) + mstore(add(indicesEnd, w), mload(subject)) + mstore(indices, add(mload(indices), 1)) + for { let prevIndex := 0 } 1 { } { + let index := mload(indexPtr) + mstore(indexPtr, 0x60) + if iszero(eq(index, prevIndex)) { + let element := mload(0x40) + let l := sub(index, prevIndex) + mstore(element, l) // Store the length of the element. + // Copy the `subject` one word at a time, backwards. + for { let o := and(add(l, 0x1f), w) } 1 { } { + mstore(add(element, o), mload(add(add(subject, prevIndex), o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes. + // Allocate memory for the length and the bytes, rounded up to a multiple of 32. + mstore(0x40, add(element, and(add(l, 0x3f), w))) + mstore(indexPtr, element) // Store the `element` into the array. + } + prevIndex := add(index, mload(delimiter)) + indexPtr := add(indexPtr, 0x20) + if iszero(lt(indexPtr, indicesEnd)) { break } + } + result := indices + if iszero(mload(delimiter)) { + result := add(indices, 0x20) + mstore(result, sub(mload(indices), 2)) + } + } + } + + /// @dev Returns a concatenated bytes of `a` and `b`. + /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer. + function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let w := not(0x1f) + let aLen := mload(a) + // Copy `a` one word at a time, backwards. + for { let o := and(add(aLen, 0x20), w) } 1 { } { + mstore(add(result, o), mload(add(a, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + let bLen := mload(b) + let output := add(result, aLen) + // Copy `b` one word at a time, backwards. + for { let o := and(add(bLen, 0x20), w) } 1 { } { + mstore(add(output, o), mload(add(b, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + let totalLen := add(aLen, bLen) + let last := add(add(result, 0x20), totalLen) + mstore(last, 0) // Zeroize the slot after the bytes. + mstore(result, totalLen) // Store the length. + mstore(0x40, add(last, 0x20)) // Allocate memory. + } + } + + /// @dev Returns whether `a` equals `b`. + function eq(bytes memory a, bytes memory b) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) + } + } + + /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes. + function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + // These should be evaluated on compile time, as far as possible. + let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. + let x := not(or(m, or(b, add(m, and(b, m))))) + let r := shl(7, iszero(iszero(shr(128, x)))) + r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + // forgefmt: disable-next-item + result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), + xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) + } + } + + /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. + /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. + function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) { + /// @solidity memory-safe-assembly + assembly { + let aLen := mload(a) + let bLen := mload(b) + let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f)) + if n { + for { let i := 0x20 } 1 { } { + let x := mload(add(a, i)) + let y := mload(add(b, i)) + if iszero(or(xor(x, y), eq(i, n))) { + i := add(i, 0x20) + continue + } + result := sub(gt(x, y), lt(x, y)) + break + } + } + // forgefmt: disable-next-item + if iszero(result) { + let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201 + let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0))) + let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0))) + result := sub(gt(x, y), lt(x, y)) + if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) } + } + } + } + + /// @dev Directly returns `a` without copying. + function directReturn(bytes memory a) internal pure { + /// @solidity memory-safe-assembly + assembly { + // Assumes that the bytes does not start from the scratch space. + let retStart := sub(a, 0x20) + let retUnpaddedSize := add(mload(a), 0x40) + // Right pad with zeroes. Just in case the bytes is produced + // by a method that doesn't zero right pad. + mstore(add(retStart, retUnpaddedSize), 0) + mstore(retStart, 0x20) // Store the return offset. + // End the transaction, returning the bytes. + return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) + } + } + + /// @dev Directly returns `a` with minimal copying. + function directReturn(bytes[] memory a) internal pure { + /// @solidity memory-safe-assembly + assembly { + let n := mload(a) // `a.length`. + let o := add(a, 0x20) // Start of elements in `a`. + let u := a // Highest memory slot. + let w := not(0x1f) + for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { + let c := add(o, shl(5, i)) // Location of pointer to `a[i]`. + let s := mload(c) // `a[i]`. + let l := mload(s) // `a[i].length`. + let r := and(l, 0x1f) // `a[i].length % 32`. + let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`. + // If `s` comes before `o`, or `s` is not zero right padded. + if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) { + let m := mload(0x40) + mstore(m, l) // Copy `a[i].length`. + for { } 1 { } { + mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards. + z := add(z, w) // `sub(z, 0x20)`. + if iszero(z) { break } + } + let e := add(add(m, 0x20), l) + mstore(e, 0) // Zeroize the slot after the copied bytes. + mstore(0x40, add(e, 0x20)) // Allocate memory. + s := m + } + mstore(c, sub(s, o)) // Convert to calldata offset. + let t := add(l, add(s, 0x20)) + if iszero(lt(t, u)) { u := t } + } + let retStart := add(a, w) // Assumes `a` doesn't start from scratch space. + mstore(retStart, 0x20) // Store the return offset. + return(retStart, add(0x40, sub(u, retStart))) // End the transaction. + } + } + + /// @dev Returns the word at `offset`, without any bounds checks. + function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(add(add(a, 0x20), offset)) + } + } + + /// @dev Returns the word at `offset`, without any bounds checks. + function loadCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + result := calldataload(add(a.offset, offset)) + } + } + + /// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks. + function staticStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + let l := sub(a.length, 0x20) + result.offset := add(a.offset, offset) + result.length := sub(a.length, offset) + if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) } + } + } + + /// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks. + function dynamicStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + let l := sub(a.length, 0x20) + let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. + result.offset := add(a.offset, s) + result.length := sub(a.length, s) + if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) } + } + } + + /// @dev Returns bytes in calldata. Performs bounds checks. + function bytesInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + let l := sub(a.length, 0x20) + let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. + result.offset := add(add(a.offset, s), 0x20) + result.length := calldataload(add(a.offset, s)) + // forgefmt: disable-next-item + if or(shr(64, or(result.length, or(s, or(l, a.offset)))), + or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) } + } + } + + /// @dev Returns empty calldata bytes. For silencing the compiler. + function emptyCalldata() internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + result.length := 0 + } + } +} + +/// @notice Library for converting numbers into strings and other string operations. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) +/// +/// @dev Note: +/// For performance and bytecode compactness, most of the string operations are restricted to +/// byte strings (7-bit ASCII), except where otherwise specified. +/// Usage of byte string operations on charsets with runes spanning two or more bytes +/// can lead to undefined behavior. +library LibString { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRUCTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Goated string storage struct that totally MOGs, no cap, fr. + /// Uses less gas and bytecode than Solidity's native string storage. It's meta af. + /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. + struct StringStorage { + bytes32 _spacer; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The length of the output is too small to contain all the hex digits. + error HexLengthInsufficient(); + + /// @dev The length of the string is more than 32 bytes. + error TooBigForSmallString(); + + /// @dev The input string must be a 7-bit ASCII. + error StringNot7BitASCII(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The constant returned when the `search` is not found in the string. + uint256 internal constant NOT_FOUND = type(uint256).max; + + /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. + uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; + + /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. + uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; + + /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. + uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; + + /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; + + /// @dev Lookup for '0123456789'. + uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; + + /// @dev Lookup for '0123456789abcdefABCDEF'. + uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; + + /// @dev Lookup for '01234567'. + uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; + + /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. + uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; + + /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. + uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; + + /// @dev Lookup for ' \t\n\r\x0b\x0c'. + uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRING STORAGE OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Sets the value of the string storage `$` to `s`. + function set(StringStorage storage $, string memory s) internal { + LibBytes.set(bytesStorage($), bytes(s)); + } + + /// @dev Sets the value of the string storage `$` to `s`. + function setCalldata(StringStorage storage $, string calldata s) internal { + LibBytes.setCalldata(bytesStorage($), bytes(s)); + } + + /// @dev Sets the value of the string storage `$` to the empty string. + function clear(StringStorage storage $) internal { + delete $._spacer; + } + + /// @dev Returns whether the value stored is `$` is the empty string "". + function isEmpty(StringStorage storage $) internal view returns (bool) { + return uint256($._spacer) & 0xff == uint256(0); + } + + /// @dev Returns the length of the value stored in `$`. + function length(StringStorage storage $) internal view returns (uint256) { + return LibBytes.length(bytesStorage($)); + } + + /// @dev Returns the value stored in `$`. + function get(StringStorage storage $) internal view returns (string memory) { + return string(LibBytes.get(bytesStorage($))); + } + + /// @dev Helper to cast `$` to a `BytesStorage`. + function bytesStorage(StringStorage storage $) internal pure returns (LibBytes.BytesStorage storage casted) { + /// @solidity memory-safe-assembly + assembly { + casted.slot := $.slot + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* DECIMAL OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the base 10 decimal representation of `value`. + function toString(uint256 value) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but + // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. + // We will need 1 word for the trailing zeros padding, 1 word for the length, + // and 3 words for a maximum of 78 digits. + result := add(mload(0x40), 0x80) + mstore(0x40, add(result, 0x20)) // Allocate memory. + mstore(result, 0) // Zeroize the slot after the string. + + let end := result // Cache the end of the memory to calculate the length later. + let w := not(0) // Tsk. + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { let temp := value } 1 { } { + result := add(result, w) // `sub(result, 1)`. + // Store the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(result, add(48, mod(temp, 10))) + temp := div(temp, 10) // Keep dividing `temp` until zero. + if iszero(temp) { break } + } + let n := sub(end, result) + result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the base 10 decimal representation of `value`. + function toString(int256 value) internal pure returns (string memory result) { + if (value >= 0) return toString(uint256(value)); + unchecked { + result = toString(~uint256(value) + 1); + } + /// @solidity memory-safe-assembly + assembly { + // We still have some spare memory space on the left, + // as we have allocated 3 words (96 bytes) for up to 78 digits. + let n := mload(result) // Load the string length. + mstore(result, 0x2d) // Store the '-' character. + result := sub(result, 1) // Move back the string pointer by a byte. + mstore(result, add(n, 1)) // Update the string length. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HEXADECIMAL OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the hexadecimal representation of `value`, + /// left-padded to an input length of `byteCount` bytes. + /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, + /// giving a total length of `byteCount * 2 + 2` bytes. + /// Reverts if `byteCount` is too small for the output to contain all the digits. + function toHexString(uint256 value, uint256 byteCount) internal pure returns (string memory result) { + result = toHexStringNoPrefix(value, byteCount); + /// @solidity memory-safe-assembly + assembly { + let n := add(mload(result), 2) // Compute the length. + mstore(result, 0x3078) // Store the "0x" prefix. + result := sub(result, 2) // Move the pointer. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`, + /// left-padded to an input length of `byteCount` bytes. + /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte, + /// giving a total length of `byteCount * 2` bytes. + /// Reverts if `byteCount` is too small for the output to contain all the digits. + function toHexStringNoPrefix(uint256 value, uint256 byteCount) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes + // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. + // We add 0x20 to the total and round down to a multiple of 0x20. + // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. + result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f))) + mstore(0x40, add(result, 0x20)) // Allocate memory. + mstore(result, 0) // Zeroize the slot after the string. + + let end := result // Cache the end to calculate the length later. + // Store "0123456789abcdef" in scratch space. + mstore(0x0f, 0x30313233343536373839616263646566) + + let start := sub(result, add(byteCount, byteCount)) + let w := not(1) // Tsk. + let temp := value + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { } 1 { } { + result := add(result, w) // `sub(result, 2)`. + mstore8(add(result, 1), mload(and(temp, 15))) + mstore8(result, mload(and(shr(4, temp), 15))) + temp := shr(8, temp) + if iszero(xor(result, start)) { break } + } + if temp { + mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. + revert(0x1c, 0x04) + } + let n := sub(end, result) + result := sub(result, 0x20) + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. + /// As address are 20 bytes long, the output will left-padded to have + /// a length of `20 * 2 + 2` bytes. + function toHexString(uint256 value) internal pure returns (string memory result) { + result = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let n := add(mload(result), 2) // Compute the length. + mstore(result, 0x3078) // Store the "0x" prefix. + result := sub(result, 2) // Move the pointer. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x". + /// The output excludes leading "0" from the `toHexString` output. + /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. + function toMinimalHexString(uint256 value) internal pure returns (string memory result) { + result = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. + let n := add(mload(result), 2) // Compute the length. + mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. + result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero. + mstore(result, sub(n, o)) // Store the length, accounting for leading zero. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output excludes leading "0" from the `toHexStringNoPrefix` output. + /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. + function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { + result = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. + let n := mload(result) // Get the length. + result := add(result, o) // Move the pointer, accounting for leading zero. + mstore(result, sub(n, o)) // Store the length, accounting for leading zero. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is encoded using 2 hexadecimal digits per byte. + /// As address are 20 bytes long, the output will left-padded to have + /// a length of `20 * 2` bytes. + function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, + // 0x02 bytes for the prefix, and 0x40 bytes for the digits. + // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. + result := add(mload(0x40), 0x80) + mstore(0x40, add(result, 0x20)) // Allocate memory. + mstore(result, 0) // Zeroize the slot after the string. + + let end := result // Cache the end to calculate the length later. + mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. + + let w := not(1) // Tsk. + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { let temp := value } 1 { } { + result := add(result, w) // `sub(result, 2)`. + mstore8(add(result, 1), mload(and(temp, 15))) + mstore8(result, mload(and(shr(4, temp), 15))) + temp := shr(8, temp) + if iszero(temp) { break } + } + let n := sub(end, result) + result := sub(result, 0x20) + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, + /// and the alphabets are capitalized conditionally according to + /// https://eips.ethereum.org/EIPS/eip-55 + function toHexStringChecksummed(address value) internal pure returns (string memory result) { + result = toHexString(value); + /// @solidity memory-safe-assembly + assembly { + let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` + let o := add(result, 0x22) + let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` + let t := shl(240, 136) // `0b10001000 << 240` + for { let i := 0 } 1 { } { + mstore(add(i, i), mul(t, byte(i, hashed))) + i := add(i, 1) + if eq(i, 20) { break } + } + mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) + o := add(o, 0x20) + mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. + function toHexString(address value) internal pure returns (string memory result) { + result = toHexStringNoPrefix(value); + /// @solidity memory-safe-assembly + assembly { + let n := add(mload(result), 2) // Compute the length. + mstore(result, 0x3078) // Store the "0x" prefix. + result := sub(result, 2) // Move the pointer. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the hexadecimal representation of `value`. + /// The output is encoded using 2 hexadecimal digits per byte. + function toHexStringNoPrefix(address value) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + // Allocate memory. + // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, + // 0x02 bytes for the prefix, and 0x28 bytes for the digits. + // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. + mstore(0x40, add(result, 0x80)) + mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. + + result := add(result, 2) + mstore(result, 40) // Store the length. + let o := add(result, 0x20) + mstore(add(o, 40), 0) // Zeroize the slot after the string. + value := shl(96, value) + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + for { let i := 0 } 1 { } { + let p := add(o, add(i, i)) + let temp := byte(i, value) + mstore8(add(p, 1), mload(and(temp, 15))) + mstore8(p, mload(shr(4, temp))) + i := add(i, 1) + if eq(i, 20) { break } + } + } + } + + /// @dev Returns the hex encoded string from the raw bytes. + /// The output is encoded using 2 hexadecimal digits per byte. + function toHexString(bytes memory raw) internal pure returns (string memory result) { + result = toHexStringNoPrefix(raw); + /// @solidity memory-safe-assembly + assembly { + let n := add(mload(result), 2) // Compute the length. + mstore(result, 0x3078) // Store the "0x" prefix. + result := sub(result, 2) // Move the pointer. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the hex encoded string from the raw bytes. + /// The output is encoded using 2 hexadecimal digits per byte. + function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + let n := mload(raw) + result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. + mstore(result, add(n, n)) // Store the length of the output. + + mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. + let o := add(result, 0x20) + let end := add(raw, n) + for { } iszero(eq(raw, end)) { } { + raw := add(raw, 1) + mstore8(add(o, 1), mload(and(mload(raw), 15))) + mstore8(o, mload(and(shr(4, mload(raw)), 15))) + o := add(o, 2) + } + mstore(o, 0) // Zeroize the slot after the string. + mstore(0x40, add(o, 0x20)) // Allocate memory. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RUNE STRING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the number of UTF characters in the string. + function runeCount(string memory s) internal pure returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + if mload(s) { + mstore(0x00, div(not(0), 255)) + mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) + let o := add(s, 0x20) + let end := add(o, mload(s)) + for { result := 1 } 1 { result := add(result, 1) } { + o := add(o, byte(0, mload(shr(250, mload(o))))) + if iszero(lt(o, end)) { break } + } + } + } + } + + /// @dev Returns if this string is a 7-bit ASCII string. + /// (i.e. all characters codes are in [0..127]) + function is7BitASCII(string memory s) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := 1 + let mask := shl(7, div(not(0), 255)) + let n := mload(s) + if n { + let o := add(s, 0x20) + let end := add(o, n) + let last := mload(end) + mstore(end, 0) + for { } 1 { } { + if and(mask, mload(o)) { + result := 0 + break + } + o := add(o, 0x20) + if iszero(lt(o, end)) { break } + } + mstore(end, last) + } + } + } + + /// @dev Returns if this string is a 7-bit ASCII string, + /// AND all characters are in the `allowed` lookup. + /// Note: If `s` is empty, returns true regardless of `allowed`. + function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := 1 + if mload(s) { + let allowed_ := shr(128, shl(128, allowed)) + let o := add(s, 0x20) + for { let end := add(o, mload(s)) } 1 { } { + result := and(result, shr(byte(0, mload(o)), allowed_)) + o := add(o, 1) + if iszero(and(result, lt(o, end))) { break } + } + } + } + } + + /// @dev Converts the bytes in the 7-bit ASCII string `s` to + /// an allowed lookup for use in `is7BitASCII(s, allowed)`. + /// To save runtime gas, you can cache the result in an immutable variable. + function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { + /// @solidity memory-safe-assembly + assembly { + if mload(s) { + let o := add(s, 0x20) + for { let end := add(o, mload(s)) } 1 { } { + result := or(result, shl(byte(0, mload(o)), 1)) + o := add(o, 1) + if iszero(lt(o, end)) { break } + } + if shr(128, result) { + mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. + revert(0x1c, 0x04) + } + } + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTE STRING OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + // For performance and bytecode compactness, byte string operations are restricted + // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. + // Usage of byte string operations on charsets with runes spanning two or more bytes + // can lead to undefined behavior. + + /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. + function replace(string memory subject, string memory needle, string memory replacement) + internal + pure + returns (string memory) + { + return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement))); + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from left to right, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function indexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { + return LibBytes.indexOf(bytes(subject), bytes(needle), from); + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from left to right. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function indexOf(string memory subject, string memory needle) internal pure returns (uint256) { + return LibBytes.indexOf(bytes(subject), bytes(needle), 0); + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from right to left, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function lastIndexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { + return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from); + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from right to left. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function lastIndexOf(string memory subject, string memory needle) internal pure returns (uint256) { + return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max); + } + + /// @dev Returns true if `needle` is found in `subject`, false otherwise. + function contains(string memory subject, string memory needle) internal pure returns (bool) { + return LibBytes.contains(bytes(subject), bytes(needle)); + } + + /// @dev Returns whether `subject` starts with `needle`. + function startsWith(string memory subject, string memory needle) internal pure returns (bool) { + return LibBytes.startsWith(bytes(subject), bytes(needle)); + } + + /// @dev Returns whether `subject` ends with `needle`. + function endsWith(string memory subject, string memory needle) internal pure returns (bool) { + return LibBytes.endsWith(bytes(subject), bytes(needle)); + } + + /// @dev Returns `subject` repeated `times`. + function repeat(string memory subject, uint256 times) internal pure returns (string memory) { + return string(LibBytes.repeat(bytes(subject), times)); + } + + /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). + /// `start` and `end` are byte offsets. + function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory) { + return string(LibBytes.slice(bytes(subject), start, end)); + } + + /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. + /// `start` is a byte offset. + function slice(string memory subject, uint256 start) internal pure returns (string memory) { + return string(LibBytes.slice(bytes(subject), start, type(uint256).max)); + } + + /// @dev Returns all the indices of `needle` in `subject`. + /// The indices are byte offsets. + function indicesOf(string memory subject, string memory needle) internal pure returns (uint256[] memory) { + return LibBytes.indicesOf(bytes(subject), bytes(needle)); + } + + /// @dev Returns an arrays of strings based on the `delimiter` inside of the `subject` string. + function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { + bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter)); + /// @solidity memory-safe-assembly + assembly { + result := a + } + } + + /// @dev Returns a concatenated string of `a` and `b`. + /// Cheaper than `string.concat()` and does not de-align the free memory pointer. + function concat(string memory a, string memory b) internal pure returns (string memory) { + return string(LibBytes.concat(bytes(a), bytes(b))); + } + + /// @dev Returns a copy of the string in either lowercase or UPPERCASE. + /// WARNING! This function is only compatible with 7-bit ASCII strings. + function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + let n := mload(subject) + if n { + result := mload(0x40) + let o := add(result, 0x20) + let d := sub(subject, result) + let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) + for { let end := add(o, n) } 1 { } { + let b := byte(0, mload(add(d, o))) + mstore8(o, xor(and(shr(b, flags), 0x20), b)) + o := add(o, 1) + if eq(o, end) { break } + } + mstore(result, n) // Store the length. + mstore(o, 0) // Zeroize the slot after the string. + mstore(0x40, add(o, 0x20)) // Allocate memory. + } + } + } + + /// @dev Returns a string from a small bytes32 string. + /// `s` must be null-terminated, or behavior will be undefined. + function fromSmallString(bytes32 s) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let n := 0 + for { } byte(n, s) { n := add(n, 1) } { } // Scan for '\0'. + mstore(result, n) // Store the length. + let o := add(result, 0x20) + mstore(o, s) // Store the bytes of the string. + mstore(add(o, n), 0) // Zeroize the slot after the string. + mstore(0x40, add(result, 0x40)) // Allocate memory. + } + } + + /// @dev Returns the small string, with all bytes after the first null byte zeroized. + function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + for { } byte(result, s) { result := add(result, 1) } { } // Scan for '\0'. + mstore(0x00, s) + mstore(result, 0x00) + result := mload(0x00) + } + } + + /// @dev Returns the string as a normalized null-terminated small string. + function toSmallString(string memory s) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(s) + if iszero(lt(result, 33)) { + mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. + revert(0x1c, 0x04) + } + result := shl(shl(3, sub(32, result)), mload(add(s, result))) + } + } + + /// @dev Returns a lowercased copy of the string. + /// WARNING! This function is only compatible with 7-bit ASCII strings. + function lower(string memory subject) internal pure returns (string memory result) { + result = toCase(subject, false); + } + + /// @dev Returns an UPPERCASED copy of the string. + /// WARNING! This function is only compatible with 7-bit ASCII strings. + function upper(string memory subject) internal pure returns (string memory result) { + result = toCase(subject, true); + } + + /// @dev Escapes the string to be used within HTML tags. + function escapeHTML(string memory s) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let end := add(s, mload(s)) + let o := add(result, 0x20) + // Store the bytes of the packed offsets and strides into the scratch space. + // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. + mstore(0x1f, 0x900094) + mstore(0x08, 0xc0000000a6ab) + // Store ""&'<>" into the scratch space. + mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) + for { } iszero(eq(s, end)) { } { + s := add(s, 1) + let c := and(mload(s), 0xff) + // Not in `["\"","'","&","<",">"]`. + if iszero(and(shl(c, 1), 0x500000c400000000)) { + mstore8(o, c) + o := add(o, 1) + continue + } + let t := shr(248, mload(c)) + mstore(o, mload(and(t, 0x1f))) + o := add(o, shr(5, t)) + } + mstore(o, 0) // Zeroize the slot after the string. + mstore(result, sub(o, add(result, 0x20))) // Store the length. + mstore(0x40, add(o, 0x20)) // Allocate memory. + } + } + + /// @dev Escapes the string to be used within double-quotes in a JSON. + /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. + function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let o := add(result, 0x20) + if addDoubleQuotes { + mstore8(o, 34) + o := add(1, o) + } + // Store "\\u0000" in scratch space. + // Store "0123456789abcdef" in scratch space. + // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. + // into the scratch space. + mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) + // Bitmask for detecting `["\"","\\"]`. + let e := or(shl(0x22, 1), shl(0x5c, 1)) + for { let end := add(s, mload(s)) } iszero(eq(s, end)) { } { + s := add(s, 1) + let c := and(mload(s), 0xff) + if iszero(lt(c, 0x20)) { + if iszero(and(shl(c, 1), e)) { + // Not in `["\"","\\"]`. + mstore8(o, c) + o := add(o, 1) + continue + } + mstore8(o, 0x5c) // "\\". + mstore8(add(o, 1), c) + o := add(o, 2) + continue + } + if iszero(and(shl(c, 1), 0x3700)) { + // Not in `["\b","\t","\n","\f","\d"]`. + mstore8(0x1d, mload(shr(4, c))) // Hex value. + mstore8(0x1e, mload(and(c, 15))) // Hex value. + mstore(o, mload(0x19)) // "\\u00XX". + o := add(o, 6) + continue + } + mstore8(o, 0x5c) // "\\". + mstore8(add(o, 1), mload(add(c, 8))) + o := add(o, 2) + } + if addDoubleQuotes { + mstore8(o, 34) + o := add(1, o) + } + mstore(o, 0) // Zeroize the slot after the string. + mstore(result, sub(o, add(result, 0x20))) // Store the length. + mstore(0x40, add(o, 0x20)) // Allocate memory. + } + } + + /// @dev Escapes the string to be used within double-quotes in a JSON. + function escapeJSON(string memory s) internal pure returns (string memory result) { + result = escapeJSON(s, false); + } + + /// @dev Encodes `s` so that it can be safely used in a URI, + /// just like `encodeURIComponent` in JavaScript. + /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent + /// See: https://datatracker.ietf.org/doc/html/rfc2396 + /// See: https://datatracker.ietf.org/doc/html/rfc3986 + function encodeURIComponent(string memory s) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + // Store "0123456789ABCDEF" in scratch space. + // Uppercased to be consistent with JavaScript's implementation. + mstore(0x0f, 0x30313233343536373839414243444546) + let o := add(result, 0x20) + for { let end := add(s, mload(s)) } iszero(eq(s, end)) { } { + s := add(s, 1) + let c := and(mload(s), 0xff) + // If not in `[0-9A-Z-a-z-_.!~*'()]`. + if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) { + mstore8(o, 0x25) // '%'. + mstore8(add(o, 1), mload(and(shr(4, c), 15))) + mstore8(add(o, 2), mload(and(c, 15))) + o := add(o, 3) + continue + } + mstore8(o, c) + o := add(o, 1) + } + mstore(result, sub(o, add(result, 0x20))) // Store the length. + mstore(o, 0) // Zeroize the slot after the string. + mstore(0x40, add(o, 0x20)) // Allocate memory. + } + } + + /// @dev Returns whether `a` equals `b`. + function eq(string memory a, string memory b) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) + } + } + + /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. + function eqs(string memory a, bytes32 b) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + // These should be evaluated on compile time, as far as possible. + let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. + let x := not(or(m, or(b, add(m, and(b, m))))) + let r := shl(7, iszero(iszero(shr(128, x)))) + r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + // forgefmt: disable-next-item + result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), + xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) + } + } + + /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. + /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. + function cmp(string memory a, string memory b) internal pure returns (int256) { + return LibBytes.cmp(bytes(a), bytes(b)); + } + + /// @dev Packs a single string with its length into a single word. + /// Returns `bytes32(0)` if the length is zero or greater than 31. + function packOne(string memory a) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + // We don't need to zero right pad the string, + // since this is our own custom non-standard packing scheme. + result := + mul( + // Load the length and the bytes. + mload(add(a, 0x1f)), + // `length != 0 && length < 32`. Abuses underflow. + // Assumes that the length is valid and within the block gas limit. + lt(sub(mload(a), 1), 0x1f) + ) + } + } + + /// @dev Unpacks a string packed using {packOne}. + /// Returns the empty string if `packed` is `bytes32(0)`. + /// If `packed` is not an output of {packOne}, the output behavior is undefined. + function unpackOne(bytes32 packed) internal pure returns (string memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) // Grab the free memory pointer. + mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). + mstore(result, 0) // Zeroize the length slot. + mstore(add(result, 0x1f), packed) // Store the length and bytes. + mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. + } + } + + /// @dev Packs two strings with their lengths into a single word. + /// Returns `bytes32(0)` if combined length is zero or greater than 30. + function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + let aLen := mload(a) + // We don't need to zero right pad the strings, + // since this is our own custom non-standard packing scheme. + result := + mul( + or( // Load the length and the bytes of `a` and `b`. + shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))), + // `totalLen != 0 && totalLen < 31`. Abuses underflow. + // Assumes that the lengths are valid and within the block gas limit. + lt(sub(add(aLen, mload(b)), 1), 0x1e) + ) + } + } + + /// @dev Unpacks strings packed using {packTwo}. + /// Returns the empty strings if `packed` is `bytes32(0)`. + /// If `packed` is not an output of {packTwo}, the output behavior is undefined. + function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { + /// @solidity memory-safe-assembly + assembly { + resultA := mload(0x40) // Grab the free memory pointer. + resultB := add(resultA, 0x40) + // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. + mstore(0x40, add(resultB, 0x40)) + // Zeroize the length slots. + mstore(resultA, 0) + mstore(resultB, 0) + // Store the lengths and bytes. + mstore(add(resultA, 0x1f), packed) + mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) + // Right pad with zeroes. + mstore(add(add(resultA, 0x20), mload(resultA)), 0) + mstore(add(add(resultB, 0x20), mload(resultB)), 0) + } + } + + /// @dev Directly returns `a` without copying. + function directReturn(string memory a) internal pure { + /// @solidity memory-safe-assembly + assembly { + // Assumes that the string does not start from the scratch space. + let retStart := sub(a, 0x20) + let retUnpaddedSize := add(mload(a), 0x40) + // Right pad with zeroes. Just in case the string is produced + // by a method that doesn't zero right pad. + mstore(add(retStart, retUnpaddedSize), 0) + mstore(retStart, 0x20) // Store the return offset. + // End the transaction, returning the string. + return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) + } + } +} diff --git a/patches/openvm-sdk/contracts/test/helpers/MockDeps.sol b/patches/openvm-sdk/contracts/test/helpers/MockDeps.sol new file mode 100644 index 00000000..12296534 --- /dev/null +++ b/patches/openvm-sdk/contracts/test/helpers/MockDeps.sol @@ -0,0 +1,12 @@ +interface IOpenVmHalo2Verifier { + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + external + view; +} + +contract Halo2Verifier { + /// Mock verifier always reverts + fallback(bytes calldata) external returns (bytes memory) { + revert("Verification failed"); + } +} diff --git a/patches/openvm-sdk/examples/sdk_app.rs b/patches/openvm-sdk/examples/sdk_app.rs new file mode 100644 index 00000000..e1ec30a8 --- /dev/null +++ b/patches/openvm-sdk/examples/sdk_app.rs @@ -0,0 +1,45 @@ +// [!region dependencies] +use openvm_build::GuestOptions; +use openvm_sdk::{config::AggregationSystemParams, prover::verify_app_proof, Sdk, StdIn}; +use openvm_stark_sdk::config::{app_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT}; +// [!endregion dependencies] + +#[allow(unused_variables, unused_doc_comments)] +fn main() -> eyre::Result<()> { + // [!region init] + // 1. Initialize the SDK with the standard configuration. + let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); + let agg_params = AggregationSystemParams::default(); + let sdk = Sdk::standard(app_params, agg_params); + // [!endregion init] + + // [!region build] + // 2 Build the ELF with default guest options and target filter. + let guest_opts = GuestOptions::default(); + let target_path = "your_path_project_root"; + let elf = sdk.build(guest_opts, target_path, &None, None)?; + // [!endregion build] + + let stdin = StdIn::default(); + + // [!region execution] + // 3. Run the program with default inputs. + let output = sdk.compile_and_execute(elf.clone(), stdin.clone())?; + println!("public values output: {output:?}"); + // [!endregion execution] + + // [!region proof_generation] + // 5. Generate an app proof. + let mut prover = sdk.app_prover(elf)?.with_program_name("test_program"); + let proof = prover.prove(stdin)?; + // [!endregion proof_generation] + + // [!region verification] + // 6. Do this once to save the app_vk, independent of the proof. + let (_app_pk, app_vk) = sdk.app_keygen(); + // 7. Verify your program. + let _ = verify_app_proof::(&app_vk, &proof)?; + // [!endregion verification] + + Ok(()) +} diff --git a/patches/openvm-sdk/examples/sdk_evm.rs b/patches/openvm-sdk/examples/sdk_evm.rs new file mode 100644 index 00000000..83527d62 --- /dev/null +++ b/patches/openvm-sdk/examples/sdk_evm.rs @@ -0,0 +1,71 @@ +// [!region dependencies] +use std::fs; + +use eyre::Result; +use openvm_build::GuestOptions; +use openvm_sdk::{config::AggregationSystemParams, Sdk, StdIn}; +use openvm_stark_sdk::config::{app_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct SomeStruct { + pub a: u64, + pub b: u64, +} +// [!endregion dependencies] + +#[allow(dead_code, unused_variables)] +fn read_elf() -> Result<(), Box> { + // [!region read_elf] + // 2b. Load the ELF from a file + let elf: Vec = fs::read("your_path_to_elf")?; + // [!endregion read_elf] + Ok(()) +} + +#[allow(unused_variables, unused_doc_comments)] +fn main() -> Result<(), Box> { + /// to import example guest code in crate replace `target_path` for: + /// ``` + /// use std::path::PathBuf; + /// + /// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf(); + /// path.push("guest/fib"); + /// let target_path = path.to_str().unwrap(); + /// ``` + // [!region build] + // 1. Initialize the SDK with the RV64IM preset and default aggregation parameters. + let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); + let agg_params = AggregationSystemParams::default(); + let sdk = Sdk::riscv64(app_params, agg_params); + + // 2a. Build the ELF with guest options and a target filter. + let guest_opts = GuestOptions::default(); + let target_path = "your_path_project_root"; + let elf = sdk.build(guest_opts, target_path, &None, None)?; + // [!endregion build] + + // [!region input] + // 3. Format your input into StdIn + let my_input = SomeStruct { a: 1, b: 2 }; // anything that can be serialized + let mut stdin = StdIn::default(); + stdin.write(&my_input); + // [!endregion input] + + // [!region evm_verification] + // 5. Generate the SNARK verifier smart contract + let verifier = sdk.generate_halo2_verifier_solidity()?; + + // 6. Generate an EVM proof + // NOTE: if they have not been initialized already, this call will lazily generate the app, + // aggregation, root, and Halo2 proving keys before producing the final EVM proof. + let proof = sdk.prove_evm(elf, stdin, &[])?; + + // 7. Verify the EVM proof + // NOTE: you may compare the proof's executable and VM commits against an expected value by + // passing Some(app_commit) — e.g. `sdk.app_commit(elf)?` instead of None. + Sdk::verify_evm_halo2_proof(&verifier, proof, None)?; + // [!endregion evm_verification] + + Ok(()) +} diff --git a/patches/openvm-sdk/examples/sdk_stark.rs b/patches/openvm-sdk/examples/sdk_stark.rs new file mode 100644 index 00000000..175e2f50 --- /dev/null +++ b/patches/openvm-sdk/examples/sdk_stark.rs @@ -0,0 +1,79 @@ +// [!region dependencies] +use std::fs; + +use openvm_build::GuestOptions; +use openvm_sdk::{config::AggregationSystemParams, Sdk, StdIn}; +use openvm_stark_sdk::config::{app_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct SomeStruct { + pub a: u64, + pub b: u64, +} +// [!endregion dependencies] + +#[allow(dead_code, unused_variables)] +fn read_elf() -> eyre::Result<()> { + // [!region read_elf] + // 2b. Load the ELF from a file + let elf: Vec = fs::read("your_path_to_elf")?; + // [!endregion read_elf] + Ok(()) +} + +#[allow(unused_variables, unused_doc_comments)] +fn main() -> eyre::Result<()> { + /// to import example guest code in crate replace `target_path` for: + /// ``` + /// use std::path::PathBuf; + /// + /// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf(); + /// path.push("guest/fib"); + /// let target_path = path.to_str().unwrap(); + /// ``` + // [!region build] + // 1. Initialize the SDK with the RV64IM preset and default aggregation parameters. + let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); + let agg_params = AggregationSystemParams::default(); + let sdk = Sdk::riscv64(app_params, agg_params); + + // 2a. Build the ELF with guest options and a target filter. + let guest_opts = GuestOptions::default(); + let target_path = "your_path_project_root"; + let elf = sdk.build(guest_opts, target_path, &None, None)?; + // [!endregion build] + + // [!region transpilation] + let exe = sdk.convert_to_exe(elf.clone())?; + // [!endregion transpilation] + + // [!region execution] + // 3. Format your input into StdIn + let my_input = SomeStruct { a: 1, b: 2 }; // anything that can be serialized + let mut stdin = StdIn::default(); + stdin.write(&my_input); + + // 4. Run the program + let output = sdk.compile_and_execute(exe.clone(), stdin.clone())?; + println!("public values output: {output:?}"); + // [!endregion execution] + + // [!region proof_generation] + // 5a. Generate a proof and verification baseline directly. + let (proof, baseline) = sdk.prove(exe.clone(), stdin.clone(), &[])?; + // 5b. Or build a StarkProver with custom fields and generate the baseline separately. + let mut prover = sdk.prover(exe)?.with_program_name("test_program"); + let baseline = prover.generate_baseline(); + let (proof, _metadata) = prover.prove(stdin.clone(), &[])?; + // [!endregion proof_generation] + + // [!region verification] + // 6. Do this once to save the aggregation VK, independent of the proof. + let (_agg_pk, agg_vk) = sdk.agg_keygen(); + // 7. Verify your program. + Sdk::verify_proof(agg_vk, baseline, &proof)?; + // [!endregion verification] + + Ok(()) +} diff --git a/patches/openvm-sdk/guest/fib/Cargo.toml b/patches/openvm-sdk/guest/fib/Cargo.toml new file mode 100644 index 00000000..5e8e1924 --- /dev/null +++ b/patches/openvm-sdk/guest/fib/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +resolver = "2" + +[package] +name = "openvm-sdk-example-test" +version = "0.0.0" +edition = "2021" + +[dependencies] +openvm = { path = "../../../toolchain/openvm" } + +[features] +default = [] +std = ["openvm/std"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } diff --git a/patches/openvm-sdk/guest/fib/openvm.toml b/patches/openvm-sdk/guest/fib/openvm.toml new file mode 100644 index 00000000..2c3d9e30 --- /dev/null +++ b/patches/openvm-sdk/guest/fib/openvm.toml @@ -0,0 +1,3 @@ +[app_vm_config.rv64i] +[app_vm_config.rv64m] +[app_vm_config.io] diff --git a/patches/openvm-sdk/guest/fib/src/main.rs b/patches/openvm-sdk/guest/fib/src/main.rs new file mode 100644 index 00000000..d7da9a93 --- /dev/null +++ b/patches/openvm-sdk/guest/fib/src/main.rs @@ -0,0 +1,40 @@ +#![cfg_attr( + all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), + no_main +)] +#![cfg_attr(not(feature = "std"), no_std)] + +openvm::entry!(main); + +fn fibonacci(n: u64) -> (u64, u64) { + if n <= 1 { + return (0, n); + } + let mut a: u64 = 0; + let mut b: u64 = 1; + for _ in 2..=n { + let sum = a + b; + a = b; + b = sum; + } + (a, b) +} + +pub fn main() { + // arbitrary n that results in more than 1 segment + let n = core::hint::black_box(1 << 5); + + let mut a = 0; + let mut b = 0; + // calculate nth fibonacci number n times + for _ in 0..n { + (a, b) = fibonacci(n); + } + + if a == 0 { + panic!(); + } + + openvm::io::reveal_u64(a, 0); + openvm::io::reveal_u64(b, 1); +} diff --git a/patches/openvm-sdk/guest/little/Cargo.toml b/patches/openvm-sdk/guest/little/Cargo.toml new file mode 100644 index 00000000..38b59551 --- /dev/null +++ b/patches/openvm-sdk/guest/little/Cargo.toml @@ -0,0 +1,25 @@ +[workspace] +resolver = "2" + +[package] +name = "openvm-sdk-little-test" +version = "0.0.0" +edition = "2021" + +[dependencies] +openvm = { path = "../../../toolchain/openvm" } +openvm-algebra-guest = { path = "../../../../extensions/algebra/guest" } +openvm-ecc-guest = { path = "../../../../extensions/ecc/guest" } +openvm-pairing = { path = "../../../../guest-libs/pairing", features = [ + "bn254", + "bls12_381", +] } +openvm-k256 = { path = "../../../../guest-libs/k256", package = "k256" } +openvm-p256 = { path = "../../../../guest-libs/p256", package = "p256" } + +[features] +default = [] +std = ["openvm/std"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } diff --git a/patches/openvm-sdk/guest/little/openvm.toml b/patches/openvm-sdk/guest/little/openvm.toml new file mode 100644 index 00000000..13094559 --- /dev/null +++ b/patches/openvm-sdk/guest/little/openvm.toml @@ -0,0 +1,72 @@ +[app_vm_config.rv64i] +[app_vm_config.rv64m] +[app_vm_config.io] + +[app_vm_config.keccak] +[app_vm_config.sha2] +[app_vm_config.bigint] + +[app_vm_config.modular] +supported_moduli = [ + # bn254 (alt bn128) + "21888242871839275222246405745257275088696311157297823662689037894645226208583", # coordinate field + "21888242871839275222246405745257275088548364400416034343698204186575808495617", # scalar field + # secp256k1 (k256) + "115792089237316195423570985008687907853269984665640564039457584007908834671663", # coordinate field + "115792089237316195423570985008687907852837564279074904382605163141518161494337", # scalar field + # secp256r1 (p256) + "115792089210356248762697446949407573530086143415290314195533631308867097853951", # coordinate + "115792089210356248762697446949407573529996955224135760342422259061068512044369", # scalar + # bls12_381 + "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", # coordinate field + "52435875175126190479447740508185965837690552500527637822603658699938581184513", # scalar field +] + +[app_vm_config.fp2] +supported_moduli = [ + [ + "Bn254Fp2", + # bn254 (alt bn128) + "21888242871839275222246405745257275088696311157297823662689037894645226208583", + ], + # Bls12_381 + [ + "Bls12_381Fp2", + "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", + ], +] + +# bn254 (alt bn128) +[[app_vm_config.ecc.supported_curves]] +struct_name = "Bn254G1Affine" +modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583" +scalar = "21888242871839275222246405745257275088548364400416034343698204186575808495617" +a = "0" +b = "3" + +# secp256k1 (k256) +[[app_vm_config.ecc.supported_curves]] +struct_name = "Secp256k1Point" +modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" +scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" +a = "0" +b = "7" + +# secp256r1 (p256) +[[app_vm_config.ecc.supported_curves]] +struct_name = "P256Point" +modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" +scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" +a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" +b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" + +# bls12_381 +[[app_vm_config.ecc.supported_curves]] +struct_name = "Bls12_381G1Affine" +modulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787" +scalar = "52435875175126190479447740508185965837690552500527637822603658699938581184513" +a = "0" +b = "4" + +[app_vm_config.pairing] +supported_curves = ["Bn254", "Bls12_381"] diff --git a/patches/openvm-sdk/guest/little/openvm_init.rs b/patches/openvm-sdk/guest/little/openvm_init.rs new file mode 100644 index 00000000..257afb31 --- /dev/null +++ b/patches/openvm-sdk/guest/little/openvm_init.rs @@ -0,0 +1,4 @@ +// This file is automatically generated by cargo openvm. Do not rename or edit. +openvm_algebra_guest::moduli_macros::moduli_init! { "21888242871839275222246405745257275088696311157297823662689037894645226208583", "21888242871839275222246405745257275088548364400416034343698204186575808495617", "115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "115792089210356248762697446949407573530086143415290314195533631308867097853951", "115792089210356248762697446949407573529996955224135760342422259061068512044369", "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", "52435875175126190479447740508185965837690552500527637822603658699938581184513" } +openvm_algebra_guest::complex_macros::complex_init! { "Bn254Fp2" { mod_idx = 0 }, "Bls12_381Fp2" { mod_idx = 6 } } +openvm_ecc_guest::sw_macros::sw_init! { "Bn254G1Affine", "Secp256k1Point", "P256Point", "Bls12_381G1Affine" } diff --git a/patches/openvm-sdk/guest/little/src/main.rs b/patches/openvm-sdk/guest/little/src/main.rs new file mode 100644 index 00000000..2e72aea9 --- /dev/null +++ b/patches/openvm-sdk/guest/little/src/main.rs @@ -0,0 +1,49 @@ +#![cfg_attr( + all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), + no_main +)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use openvm_algebra_guest::IntMod; +use openvm_k256::{Secp256k1Coord, Secp256k1Scalar}; +use openvm_p256::{P256Coord, P256Scalar}; +use openvm_pairing::{bls12_381::Bls12_381Fp, bn254::Bn254Fp}; + +openvm::entry!(main); +openvm::init!(); + +// Based on https://en.wikipedia.org/wiki/Fermat%27s_little_theorem. If this +// fails, then F::MODULUS is not prime. +fn fermat() +where + F::Repr: AsRef<[u8]>, +{ + let mut pow = F::MODULUS; + pow.as_mut()[0] -= 2; + + let a = F::from_u32(1234); + let mut res = F::ONE; + let mut mut_a = a.clone(); + + for pow_byte in pow.as_ref() { + for j in 0..8 { + if pow_byte & (1 << j) != 0 { + res *= &mut_a; + } + mut_a *= mut_a.clone(); + } + } + + assert_eq!(res * a, F::ONE); +} + +pub fn main() { + fermat::(); + fermat::(); + fermat::(); + fermat::(); + fermat::(); + fermat::(); +} diff --git a/patches/openvm-sdk/guest/p256/Cargo.toml b/patches/openvm-sdk/guest/p256/Cargo.toml new file mode 100644 index 00000000..290469a7 --- /dev/null +++ b/patches/openvm-sdk/guest/p256/Cargo.toml @@ -0,0 +1,31 @@ +[workspace] +resolver = "2" + +[package] +name = "openvm-sdk-p256-test" +version = "0.0.0" +edition = "2021" + +[dependencies] +openvm = { path = "../../../toolchain/openvm" } +openvm-algebra-guest = { path = "../../../../extensions/algebra/guest" } +openvm-ecc-guest = { path = "../../../../extensions/ecc/guest" } +openvm-pairing = { path = "../../../../guest-libs/pairing", features = [ + "bn254", + "bls12_381", +] } +openvm-k256 = { path = "../../../../guest-libs/k256", package = "k256" } +openvm-p256 = { path = "../../../../guest-libs/p256", package = "p256" } + +elliptic-curve = { version = "0.13.8" } + +[features] +default = [] +std = ["openvm/std"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } + +[profile.release] +panic = "abort" +lto = "thin" diff --git a/patches/openvm-sdk/guest/p256/openvm.toml b/patches/openvm-sdk/guest/p256/openvm.toml new file mode 100644 index 00000000..13094559 --- /dev/null +++ b/patches/openvm-sdk/guest/p256/openvm.toml @@ -0,0 +1,72 @@ +[app_vm_config.rv64i] +[app_vm_config.rv64m] +[app_vm_config.io] + +[app_vm_config.keccak] +[app_vm_config.sha2] +[app_vm_config.bigint] + +[app_vm_config.modular] +supported_moduli = [ + # bn254 (alt bn128) + "21888242871839275222246405745257275088696311157297823662689037894645226208583", # coordinate field + "21888242871839275222246405745257275088548364400416034343698204186575808495617", # scalar field + # secp256k1 (k256) + "115792089237316195423570985008687907853269984665640564039457584007908834671663", # coordinate field + "115792089237316195423570985008687907852837564279074904382605163141518161494337", # scalar field + # secp256r1 (p256) + "115792089210356248762697446949407573530086143415290314195533631308867097853951", # coordinate + "115792089210356248762697446949407573529996955224135760342422259061068512044369", # scalar + # bls12_381 + "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", # coordinate field + "52435875175126190479447740508185965837690552500527637822603658699938581184513", # scalar field +] + +[app_vm_config.fp2] +supported_moduli = [ + [ + "Bn254Fp2", + # bn254 (alt bn128) + "21888242871839275222246405745257275088696311157297823662689037894645226208583", + ], + # Bls12_381 + [ + "Bls12_381Fp2", + "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", + ], +] + +# bn254 (alt bn128) +[[app_vm_config.ecc.supported_curves]] +struct_name = "Bn254G1Affine" +modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583" +scalar = "21888242871839275222246405745257275088548364400416034343698204186575808495617" +a = "0" +b = "3" + +# secp256k1 (k256) +[[app_vm_config.ecc.supported_curves]] +struct_name = "Secp256k1Point" +modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" +scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" +a = "0" +b = "7" + +# secp256r1 (p256) +[[app_vm_config.ecc.supported_curves]] +struct_name = "P256Point" +modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" +scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" +a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" +b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" + +# bls12_381 +[[app_vm_config.ecc.supported_curves]] +struct_name = "Bls12_381G1Affine" +modulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787" +scalar = "52435875175126190479447740508185965837690552500527637822603658699938581184513" +a = "0" +b = "4" + +[app_vm_config.pairing] +supported_curves = ["Bn254", "Bls12_381"] diff --git a/patches/openvm-sdk/guest/p256/openvm_init.rs b/patches/openvm-sdk/guest/p256/openvm_init.rs new file mode 100644 index 00000000..257afb31 --- /dev/null +++ b/patches/openvm-sdk/guest/p256/openvm_init.rs @@ -0,0 +1,4 @@ +// This file is automatically generated by cargo openvm. Do not rename or edit. +openvm_algebra_guest::moduli_macros::moduli_init! { "21888242871839275222246405745257275088696311157297823662689037894645226208583", "21888242871839275222246405745257275088548364400416034343698204186575808495617", "115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "115792089210356248762697446949407573530086143415290314195533631308867097853951", "115792089210356248762697446949407573529996955224135760342422259061068512044369", "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", "52435875175126190479447740508185965837690552500527637822603658699938581184513" } +openvm_algebra_guest::complex_macros::complex_init! { "Bn254Fp2" { mod_idx = 0 }, "Bls12_381Fp2" { mod_idx = 6 } } +openvm_ecc_guest::sw_macros::sw_init! { "Bn254G1Affine", "Secp256k1Point", "P256Point", "Bls12_381G1Affine" } diff --git a/patches/openvm-sdk/guest/p256/src/main.rs b/patches/openvm-sdk/guest/p256/src/main.rs new file mode 100644 index 00000000..05ea9e75 --- /dev/null +++ b/patches/openvm-sdk/guest/p256/src/main.rs @@ -0,0 +1,42 @@ +#![cfg_attr( + all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), + no_main +)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use elliptic_curve::{ops::LinearCombination, CurveArithmetic, Field, Group, PrimeField}; +use openvm_p256::{NistP256, P256Point, P256Scalar as Scalar}; + +openvm::entry!(main); +openvm::init!(); + +pub fn main() { + let g = P256Point::generator(); + let a = P256Point::lincomb(&g, &Scalar::from_u128(100), &g, &Scalar::from_u128(156)); + let mut b = g; + for _ in 0..8 { + b += b; + } + assert_eq!(a, b); + + type NistScalar = ::Scalar; + + let a = NistScalar::from_u128(4); + let b = a.sqrt().unwrap(); + assert!(b == NistScalar::from_u128(2) || b == -NistScalar::from_u128(2)); + + let a = NistScalar::from_u128(5); + let b = a.sqrt().unwrap(); + let sqrt_5 = NistScalar::from_str_vartime( + "37706888570942939511621860890978929712654002332559277021296980149138421130241", + ) + .unwrap(); + assert!(b == sqrt_5 || b == -sqrt_5); + assert!(b * b == a); + + let a = NistScalar::from_u128(7); + let b = a.sqrt(); + assert!(bool::from(b.is_none())); +} diff --git a/patches/openvm-sdk/openvm_riscv64.toml b/patches/openvm-sdk/openvm_riscv64.toml new file mode 100644 index 00000000..2c3d9e30 --- /dev/null +++ b/patches/openvm-sdk/openvm_riscv64.toml @@ -0,0 +1,3 @@ +[app_vm_config.rv64i] +[app_vm_config.rv64m] +[app_vm_config.io] diff --git a/patches/openvm-sdk/openvm_standard.toml b/patches/openvm-sdk/openvm_standard.toml new file mode 100644 index 00000000..13094559 --- /dev/null +++ b/patches/openvm-sdk/openvm_standard.toml @@ -0,0 +1,72 @@ +[app_vm_config.rv64i] +[app_vm_config.rv64m] +[app_vm_config.io] + +[app_vm_config.keccak] +[app_vm_config.sha2] +[app_vm_config.bigint] + +[app_vm_config.modular] +supported_moduli = [ + # bn254 (alt bn128) + "21888242871839275222246405745257275088696311157297823662689037894645226208583", # coordinate field + "21888242871839275222246405745257275088548364400416034343698204186575808495617", # scalar field + # secp256k1 (k256) + "115792089237316195423570985008687907853269984665640564039457584007908834671663", # coordinate field + "115792089237316195423570985008687907852837564279074904382605163141518161494337", # scalar field + # secp256r1 (p256) + "115792089210356248762697446949407573530086143415290314195533631308867097853951", # coordinate + "115792089210356248762697446949407573529996955224135760342422259061068512044369", # scalar + # bls12_381 + "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", # coordinate field + "52435875175126190479447740508185965837690552500527637822603658699938581184513", # scalar field +] + +[app_vm_config.fp2] +supported_moduli = [ + [ + "Bn254Fp2", + # bn254 (alt bn128) + "21888242871839275222246405745257275088696311157297823662689037894645226208583", + ], + # Bls12_381 + [ + "Bls12_381Fp2", + "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", + ], +] + +# bn254 (alt bn128) +[[app_vm_config.ecc.supported_curves]] +struct_name = "Bn254G1Affine" +modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583" +scalar = "21888242871839275222246405745257275088548364400416034343698204186575808495617" +a = "0" +b = "3" + +# secp256k1 (k256) +[[app_vm_config.ecc.supported_curves]] +struct_name = "Secp256k1Point" +modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" +scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" +a = "0" +b = "7" + +# secp256r1 (p256) +[[app_vm_config.ecc.supported_curves]] +struct_name = "P256Point" +modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" +scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" +a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" +b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" + +# bls12_381 +[[app_vm_config.ecc.supported_curves]] +struct_name = "Bls12_381G1Affine" +modulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787" +scalar = "52435875175126190479447740508185965837690552500527637822603658699938581184513" +a = "0" +b = "4" + +[app_vm_config.pairing] +supported_curves = ["Bn254", "Bls12_381"] diff --git a/patches/openvm-sdk/programs/Cargo.toml b/patches/openvm-sdk/programs/Cargo.toml new file mode 100644 index 00000000..7de70f13 --- /dev/null +++ b/patches/openvm-sdk/programs/Cargo.toml @@ -0,0 +1,23 @@ +[workspace] +resolver = "2" + +[package] +name = "openvm-sdk-test-programs" +version = "0.0.0" +edition = "2021" + +[dependencies] +openvm = { path = "../../toolchain/openvm", default-features = false } +openvm-deferral-guest = { path = "../../../extensions/deferral/guest", default-features = false } +openvm-verify-stark-guest = { path = "../../../guest-libs/verify-stark/guest", default-features = false } + +[features] +default = [] +std = ["openvm/std"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } + +[profile.release] +panic = "abort" +lto = "thin" diff --git a/patches/openvm-sdk/programs/examples/fibonacci.elf b/patches/openvm-sdk/programs/examples/fibonacci.elf new file mode 100755 index 0000000000000000000000000000000000000000..353f65bc1d5d535b92fa8bb24c9e9ffe45e956e8 GIT binary patch literal 49008 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≫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 literal 0 HcmV?d00001 diff --git a/patches/openvm-sdk/programs/examples/verify-many.rs b/patches/openvm-sdk/programs/examples/verify-many.rs new file mode 100644 index 00000000..91c44f8d --- /dev/null +++ b/patches/openvm-sdk/programs/examples/verify-many.rs @@ -0,0 +1,33 @@ +#![cfg_attr( + all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), + no_main +)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::vec::Vec; + +use openvm::io::read; +use openvm_deferral_guest::Commit; +use openvm_verify_stark_guest::{verify_stark, ProofOutput}; + +openvm::entry!(main); + +pub fn main() { + let app_exe_commit: Commit = read(); + let app_vm_commit: Commit = read(); + let user_public_values: Vec = read(); + + let expected = ProofOutput { + app_exe_commit, + app_vm_commit, + user_public_values, + }; + + let input_commit: Commit = read(); + verify_stark::<0>(&input_commit, &expected); + verify_stark::<1>(&input_commit, &expected); + verify_stark::<3>(&input_commit, &expected); + verify_stark::<4>(&input_commit, &expected); +} diff --git a/patches/openvm-sdk/programs/examples/verify-stark.elf b/patches/openvm-sdk/programs/examples/verify-stark.elf new file mode 100644 index 0000000000000000000000000000000000000000..b32d8b99d2fe5544f7aaf07337eec0e86c5842ee GIT binary patch literal 141928 zcmeFadw7)9odWTMaj@T3;?*AJ<#uQtQ%z z$xH%LYB`2bZIv1VYP**9B?*eVO*Io}*HxSU~PSV zfBc^3SDz;i^Pcyd^F815y??*w%y%p2%v2SHrT$adNk-outC=7l1?B%4J9>qh{1;ct1JcAH8<=XYc*g=izI-=c&)({b-Fxxd+fu`!e}r>eK6$ z1}D|;pE@60ME(BO|1`$#BRKCF)c*{|NeIj{2c>-$H3n)@OKQ1 z#6Ug19tpMH$`xfGFzq5WP`+9X6#qaC6kVoqUD1VQF{jXC97@-FmleBuGm9T>8{{=6 z3zry-Z^~oNqD@TbCgWyqP?)*Q>Doj8X7{oXK7-78>;OJP>Gv`WrjdCQN zv$T@x0cVV%Y9;#FK+z9bp!iu9E?TW=#fla#Uae|V6cw=QOGAv&JK>V*vmRWbt3GlK zy5Yh3!#vDKFicW-Mu=(6)pCArniC1TPgPuf zGqY=p73c2F*)2XcLDUv9XL(^x;3c!ciR!8wZBe-&`x()hFtC?VlL^1Y>Va#}$R=Ln z2fqBwc~Up;Wv!;jVA$VQ%c;&V>q`hO<8cWWU=(`$4+Zv{n*>*v+8yS&Ci?48UasHEzTn%52JG^qm{VzX~Il(f3Rk zZ}hBQKJWMrk5;Y{Mo6tMqVRlvi2f_k|Dj?1R|1Yip!gydC<08nqB!|R zil>w$A6|LxI|ZHKyKY8s&gIeAv%)A!!Ly8b;IE;zaIv9qlljKI)5M&f7;s2@*^2qG zpBWP*ZpZC66njc5zE1&P8q75}1v&WAIW}1d6Q5elXGhzabE;Dhux9iL`H9aZ?|_%Z zI{bldc$$ZHiwMS#WPr~ylyLLfp)ulz-X9P>-I|D+ed7)+X3khY6N{}Z8n=P%C)jkp zqE{Pt5O7;o-xCL7%o*=vqSMOu-sxfih29IQqPJHQ9g`GMWA%wnBjL68puLMV;2l?o z3@Hb_Kz{u-Gy;5{#U4TaK@Lv)0s3ABo(1m~RS@55QpS<&g4_#F$xv*gq{6u~26?fT z;ol13to}a9FOFMHbN?_kx2hE@DrA@f8K!_f8R(PtPosTI;gTB}j7wbNb4V_Rwh8bZ z&3Etdr%nr#coVb(x)71r+JXRMOIdi~aM%gfz_hIckgsR!^XNTeT%c&{V4!&CV49{X zmx!pbRv7vq=!1E5&Zc6V5p>E;k_p&f$b_U0`0<5kkK|ekHqo6A8DKEyQNtgeWilsf z<OT75RKV=D{n+{psF+D6ba_DkwRQJ2T!`;1eB zXK$|H3p8#)7ygdW_;(nPBliol{T}eua&A62SP#D%vTa;iwi%yJ%eKmYxUg)?yNX96 zSEprL>s4BFglSFS3p=XR(^?|2`?&d4(53eOO&N7OkvI}!_y7M}Mujf^e?>+~Tn29) zE~7w`J+LQzuqS=6Cw;IdGhhQ*uz@VtKvtmW8&+W2{RY|%$PK^Hec-Di=G<5K84mdh z8djW@-B*jXcn-Q2zT*i#ze?jBdzstU$Q;wB+L34Q9@^C7-xV9L*X)y3OzZ;RV zr5v9(sn8`VuZuBW)pXu_@oa5CXhG)aH!)GGL2i_@`u9M)Yt~e{wWF1=OE4XLNjyOF zPhd+!cn2_IOilP;FK(W#xwG>Wnv;hixAyiW?7YR0Ej~r;9WCXG@CE68w2fw5L!T3U zIpVGE>7oPrFB3ALXlqZP_`%*l`J$e{c)d3;YD}+l;ue(~6PWX(r&W;&UIssLvxxC5 z^pAAj0J+JXS2dM*n`c$cCfUN*LB?j8v|c$b+WpD)nbeLpKiV?AXGSGAvb;X|u<;%N zzOxAD)u*8gdUz)6EZA*g9sZ)Q|AJCRl))xG?J%;-@JsRMGhlas zZ@@3*;Fse2!8fbHH$Nbr$rNj`cc2TWC*S7lpdX2c$QFY?#trxm`{!!BD#mQ$m#C@Q zMv`BA;1{CZ6L|_R2fu7mRX!d3vT3x2JxKG*Iq$_cr~{n%rFyi&eUR&g;FqJoL#;25 zXkN1cLv;U3VkPD$ej(YPg}w_F z^uDq$hbQ@k=pQ!CsX$S6Z=m?*opU5@hl`yX zJ$?~cRe6#h{KP9EjmC85Xt{Dfv+8(~S8{=ei@ax*qj|)mMZO-m1)qpbCgf1hbiS;6 zkQq&>IF{i70GE;wKAZ zFv+WV9zU^B;OSnPi$}qaBj@=S8YlkRZ~KRMYD0#{e?}eXAfzSNub#VpZV)d%ljg;B z89Kd7vN**H9xoOXJ?XSJ^+UYaarRtZ#9UIACHZN9d_6h0$6sfL#w_|Fcouw{=2<^@ z)(@V|0MBNCXMNyVA9&UR&syMF6Fh5%r$NUkN@j|0B`ikd1Mp|}F#dd!=JeWPz?T6z z_SF=B{s{d?*u+lM7_H3)E%=z`4Eng#T`T*>5ZwoIEybDJst1aUO$wgG+Q^PLTp?_q)Qy^uwg7AP*z0)@TsIkv<1XwjXX4&9A52Z2AIYqbW6&jN*b zFWJr`h40h&fpSX;jJGgGuj&kRFzN#zkvYc?m@fP^!asfIhD9=t0bgW~DTE8#Yz_v> zTL1&~-=jjN4%;izHI*jp!@*F3tn(MqN5AVlg4Z1VaUBM>~j*Y z!J2eiqznG?QDGcclKyri-4^>D_5*DxS=t&tcR$ESq4&Abf$@tpZ;T+lcV1lU+*l0a z6xVSJduc(3-qn#MER0jznW%@|Ty_OxEu8i)Xoi0|^Dx(}`$gEDRo{bmHq5-UWz%LR zHuNl|{%%eW}i1&#{Y^L6M)KiT#ri&snaDxAPVL_{Gfj ze_09N=!c)W7k%GN1ipWB!s%}xqun?b-#<(=e1As5In_Sejb5y|=G#HBDIa5)nw{|n z7QP_^?<5j|5Mn2%+OxwmFNRLtlV}L-1AXmH#E%~9buGYTJ_;StWs2w#f^9Sh9kmo< zO={5O^RLuI?XFqy!L<55tZ9Cs;;Qr2sn)z8FDTIXJPYl3 zhYl79HNw9{EU{>0obQ4$9NJ?m@?Z46j8VZ(@%*LM8|D66vHv{3josk28NWThEjY_- ztK55jTd2}&i?pBL);gWqgc)linoq^cJXqNE$@yM6zh5v2njC~}4BlN$aUkFav4lym zzsxOITj)9uN0DhxSLbNH*-*<0T7K68IxI`lVT;&|_v)94HK0YyoyEf^m+}Hjwaboz z-VUg)Hc#ChUKZp}Y8t=ov+#EZRsIJ{5eMKq*I-Xq9sBO?nv+30JEn;G0!5u`Z&J(LSqkUVmE9`ns9sfV8*TG!#q||vWftOa+K~jGw^`%!1B$(J zCEHy)x`N_)VsoJ;4*E3Lm#2iUhj5);$h22{EDU=fpx->$pzDc%v1qWt7?U7b>pZ-N zXwDRtp5QgWp>GRw-jC_rcQnEChtc`m$sV1X`5K>_4>;z6#tSM^G;Uj+h%s19n}wKx zx@gc{qbh;WXr_+jW5Zq2hn+jhWd@_E3&oi(=^+3^T9X2L%0hd89 zeO`kNO1S`o=GCTP?yA$%-O6VX^Jol;jJ7kvXgfo2aDNI8_N;3?7qn{tN9E}R`8pmR zlCVe{CHOF4(SZjY`dfqk*1+#7^f$%#4Z_QCJkZ*m2ett=#7m0X5ZBTN>J7YOB7YEx z{GS&`K|H0X&5Ln$pv_oT0bk@S#j!oU3|{U$(2Ozg-g#qG{^`PFOe!5Y2D`*L(U^o| z=Q(f~ogXpA(@Wirb5!W|5SUkUZP@}#{JHxH*4vPKdEM9F6NPX135_^L&viC3zaX{+N zuk;OY@H***czzG~0qyGy)izs*mO(>#%mmXkyuupb;91*ul*Kp2 z1`)gfDBgm~Bc?%sP!u~!{qu6i4@2l2V;LuM!Nm;DC?a4I4U`Mc&lCBDh& zgFkwLcwhAH%@Orwz)>F)1vU$pQ(U8#iI*Y24g$tEvBsmL6}Rsw><8>~^dO5rX${!D z&G2oa%=r1_4@%&G^e8+s`=D8Srm3G%hMNAtD-NKeLa3 zCc3+U58s{Q;9gC<`Lf1udPNg&z2eaXV$-mP811F2tz@pTi;bIK245Dmy3|t2e2C@m zfxg@e9rd!xwCNfPjMfJNnm*8=of-(}W6lce4NFAlR)zP14q^st&~F}q4jX_DJNv}^ zd4P+?Do~!7Uq9^M1*8k*b3Us#A?73A+;b3gMl!$D<|~dQZ0kVKU5-5KyepVZpH{0u zIT|r{Cgs;4_rGd!qx-nMY#VrNhlQAQF8E6uSJjC8XJ>-qXKwA4&|ODaLr%wFfW@Hm zcMdd|r=)JdUW}J}vrO(mC-m&6_%bsWF>>T8u~C!c^JVZc#--lFzsIKjjs2{|7-M;U zRONG{nlr{Mr2V3OOWNma9poDWTP8w><@(UihdBzz&HFSf!~V6DB=>LL4c`70{zes} zGc?X`&;(!W?cdTrF|qtK?cdD5YX8iGAHRPE*gqfk&xifX@b-_J$^C0LSwjZ)&yW4{ z|84tc_w2>~9frOtN$%gCpuN0B?w`91pV&W=seFGW@f!9lxqsb_kbxh!e=+P|6ANVS z8)(R+{W}ag*}_D|7T_B>DUU~91b&C_-K4-4#Kku1EFkdr81!=n{MYD2r2+ZakFgc{ zV8fcQVNLM7iTEz!QlEz&sxT1WH4xu55Z~3%4jbYJupxc|-}M(H6MUi?@x=`MA!aH3 z_(RN!a@*nm%}~nVL)zUxWo4Nc!FK?yWbQy*rAl$vZ$%vV5!Lyc;e+l_omJ0eOC6&6 zRX1`Y@@~kFeS|J@v+9)a|Jw?k*y@2*bRGU;%VpQ z#xc$%Mm`@!x$RIv_@^0)SU(1EyaD<3h#J2haREPai5M^b{!3@VyE9n$g|)yj;w#8? z@?_kTQ!K{It^B7`Xyj||T1CD?`90+IfLjZ;j|JPugzaO(_Ay}l7>Hfyh+XK2U1*41 zXoy{?+7}cx{DswIFZyIm4S7|HwR^Fi)<|l7@&1>3?>&C$3GLsJZv|Z1OKVw~ap|P8SdFELUUWx&q4{s~?BPNz>WYIe9$d4<^G8L@JmASB*j7%m+W6@lnu=o))#WzecVEzMuAe>^t%$Dzl@nK)?4S@LX{=nAzdC)+FN9 z+Mx4zTn)eVbi!E&pK-%U=5Ekn$G~RUz!f*_z~)-T-07>Bc#Fe^;gr`s6L#0&^U^Z{ zc@uo^*P6gLP1S$%z7pRQXfj7Wj%t47IEb5SQ>y#IgcH;(NLn0g zFg3Rma`x0eSmyF})3eu0e77=e)+?;@14eD>k z0;W2@CT=0V3dv^__vUXmso@uNroC9rhWO>|6Ub}-2>j9rp7kR>J|4WE0lvkWhj_LX zIMDmN=R) zK9FlZ{!|~vL98En#3JMor$Nt@L(dc=k62UzeFHsH4n0$hJYvym=o{#na_E`jUy#3= zAu^y_$Y(8$f(OA9%v8fokSER6;M?S$lYayG5BwHtO=}gbxiI`9WPV-=`*wPkjlru>^k8zCLd5IZd>|qcy(< zkM+3Udyer(4Dbm94C_!6<3~-*FgTcz3mWg$IRlSF`vnF zT07~gBcV(dA8j1xe*Zvx(H!I{T9GI8oASNnI~=(>dXMk`yHCIO`0f8k^y?a}K{xuJ zj29Rh`C)e1cEk$H6akx>7naHTjHyOUw@cHi^kWE8%}O z;5)KHy9YcDx^Yx9ThvWaotF(0dQNrjdto#_@jL^*BWza4e60pF7KQ(s^h3!{if?Kk z)aF(y&WV_xgSTBjV)Att!*}YGaS-vt7gXoV&Dn@4<#O;dXd*XUwODa#jY1dWa*Jid zx6I+SsHcJ~Cwm%uqX-}T0pFDs@M#nFT3-dPMa>NISdQ#0sa->p8@~m=bO?lfvh51lVnT1S6=};l=#cfw7EAb@%|Wm(n~)iIp%Bv zokE83|IR}W4!ZvB7ZCe_{+b#|%dUSNCcBz5J=uk^B<&89UE$_Oz|Zs?_)5w0EJGJM z$u4PY{q5@^*#*4AW&-TM)d#WnB<2;y}oC_ zJ@AQ@8efik7smCMdipHl!7pJPZRFbPZlwCI6EvQd9M4`7OOAIVi;st$Cg;W2$mz=W zW+msnyEFNopK3I9-t7mE8Cb(i?&Bp%igDog=jlKQ^{sCyq^9>-M$R;4220s3q zd<;1T(f!BPK*D#U+5`CVEe82%&1x97IMohQ9)xVE6yGCHDq#Ukn&Zn*$qyp=kX)k* zIdkEfNU9z1biqfz16ZksoMPfscP3@fN96k;<8_kh;Z6fKF<{!XSaq&9bx~KPI_-u} zK07z2eu!$sg3~@Krj9lFA*bd1!YDpl&<@<0?Ni0_Zsh#-voK->R1+X-kV^@5K$dhT zpl?w#Fk`?b-DnxYz*G1_GvFm!mb&DCZCk9Z%oMXWwXva;&)$O9zXU#an)#Xg5P zMygK~^ZiYAE`jo&z`py1SMP#4C2cBvnPL-p2*_DUZxbM+;CnI1DbzJXo)ibBJ=WvY zW?mgATGShuHnE%hSkf`JabE@E->1Z=-2O7E@y7c+6a9@mAVpxw~0$){*}1gx~uq7T@?&vZXEy z8^C2o9usG}a{@)MpWcCdYX_X&XAtk2gt%1??1AH>oClU0+8**XOCV#GAlBZixm{g| z2eBOI{r^=(MkVAEc&e@gwa!hdd}mp=^yS_E-R9W_b&Hw%za98DQ$$@1|3>T8K=WDZazIV@>m6GSaO{4lVEeS8dOUHp7X^I|MWQE=dSrP#W_6p z3fEYuKrc|;SC7;G9MiDpfcuOyljaUhbT&RW(Wy1P_Q7qy**XQjucBf7^1U1BJ$AWP zqIXl=7kT0d95}}J9_`wQVw<;C*yc9W>R0!YuW0{=ee*jD65tKpmA{nF}g zsk2anhIucxqmNaPjCCV*h$|%f8-_v+hGt7+%WN+bn zrec?D!S@pS{@-r&5k;GdwNF6}5axhg-vd17I8o@C6EC7pYhfC9bL9SJ3CKdCW6ZBP zPrm4fkB)bn@$Nfp2+v>J<|p2jG?3H-&gN!cxbzXlj#gFBK8A}4$6l<0^7V+-4C5cb z3>^eH@mJT?!2UB}f9v3DSzklzf!;min%Mty))+rN_hbR&1oHQ=^Py{DQ+R$ZyDa(q z7(FL^q}zg*V(gEs;UKxLy%?dhC#a8yFA4id825Q=3Lzgb7t+Xlj=plP!y=o&8oM?{?DbKI9mnbsVzdWiqrb&Lwh*|)m%fMuP&^g|yA{LLjeCeC|wB{)6ILJNQR7uZ` zJJ19h0(n)#=o`0xG57^O=wdUA`ZSnZ(GRpov<(^a!~p|-ADy*`;p`5*hjSG2J>*I) zdbbGghE$R}be4k7T*$K&@}0wYr){u7z83^;k*fxcC1uH{v1UaZmdieOJpy?$Sq}m~ z2{}*XX4?iyPs0DhyzOravs&iYld;TF^dC`Ym5hUsO){i6u;-bmH$5e++}yyleW#p( zZp?ugqO7Ie*@Ne_9v!+gm-~*Naeb(5AYW-_AwM5r=p1gp#L0%;{4jE2R*Z#fXnl}{GvIF_ zE)Xc%*GGJb*q4-juGJymab_Y%h`3mMvpEQ!1RbJoMaGBO=O|~YflkG;o*ZX3#+bYl za#*ebXD9L)@99QO&GAum*2Q^nm#)o*?xqmpvHN7WLPI1PqeFfdfYnsth!t}*J3;m#l ze&84W`abZH-piwFevO>bw*y6Ea0aIhXCoGY@3$hSPjs_&u%HR!8BJsGZa>v0CuPSZ z%I{PCF-J_HzLVzAd+K`#7QGiWY#-p9(YLVQm=AN7V@}KmeJu0j-k6hSj~ui0QjFE@ zjRhG^^NaV=Kad!6OJHlK@N=-I z&PGcI4o=t0y@ibdymL#3&0*XMywAcqM${z)$`1p!eM$Vp{tP?Az+PZ)^fSZ8=}(T+ zo5cG(V2k4SbTgD&=v>9-;UH+14$2et$u; z=SL8~ldnK=(C}2q3DiDgZ~EkVzt^}$`@+nxaii{D;IoI*Mshn6R6J^Rbd~+ zncH3qe+7UGb$6zz#E-YbrU>C|FZ>a6ThNAn&}QL`tUAl^=HEX^bH)4H`;TtwtugsC)EL;4^>Q2}xu=8&3lAkODxh&%i zpEzzyx|72`swbX^81oBGCK5~8^#1~#o_LJ2lGuRxBP!!L z!0Us?rQv&X@b9m%@Ld$kfUMc@TEhMQ>zW(BNpZh_QW0sNAqH$hK7~~0oBQ)^^9|J6 zPDXs9RIx4Wa};$$^;dva_axjJd`E3K_uZ#DOAd|>UkQ4qx;wOyT^iU@0NZ#E;#1}z z?}xoRa9rsmI70$bWhm&o}7 zMNR&{s0)*OF89L7yBIPE_T?K&GG_L#1+>3r1bH9O!;s&@7V$_=BDsIL={*hInS4Lz zocF)sJvXxDbF%%t{k|Rh-3<9Q8}e;7GkF#cw#@+SsAl*uLGIIggfEz)#UI12 zkv?kDe?5!!-2l420dzeZa`yT2uxF5u8BH}2vUZ?3q7Y4r$fRQ&FiCw)ekH|ZkYm(3b>y`dQ$ABiZd-L` zQrvqj_&beHLAB%_K41O#xcA!O_`smIhn;LbmGT$lBPvNYR<*cH1(AfprpMa0-Jc;}kXbtj| zJux@J#ER}5DK~tr7uEj~dsQ1T#hRD>Tx%tpOmPmie~S3a$yzejjqGLGYw#IfK@7lz zOf^=Z?&uGL&f(6<&Yim^$Jc8EcFlV@vjMr9HRu!JlaP}Iuq8Cq5xslniK;xHgS#djjnqGn^Q zCTw8y9{XFceP_M}8^x+XOe(b7>V|#h`%j!lIxg0zmyR>Ll&RWcHr486Q*m}=H_nW> z*HkfkS&WsDA8K|jwoCW0vNHG+*7h>H8@3=MX$@mfcjyJ49haJtbYfVL)4Z95cjd+jc-FaatvhU4^ zM;?Fb0O6GCiqiAUe3@IJOXWNU<}rJM@!94+Igj4C&#i&~F5^^~m*&xrnnUv#lSa-% zeQ!1~&!xX3oh8f|?2FcmWV}ks1$M-HUI~9D2%8$ZOg;~F(sS64TGF4E{w=;I?V=Fr zq!Iij&+N%Qi*c58hwAA>X5zgeKO8y{^=g-)W+Q!n5^6YPZMn7!e8PM)gaun>-a!rb zRLyXz&6#{&A#0hB`r&I(Kg@G-S~Nwmm!h`4c7ByubB)cllgCkGmdkI0jlXn{!k_f1 zZtY%ts;HfRS>czUMooJK-%(2+#^-Iby!URaNq$-w5B+Y#nJfB4eKxT*mweW6O6tNcO9T@sY>nQYrW{R{d)Otl^M?a z?_Fyb79!U^OZujwcJGHYf4JO&U7w3$%^If7+m160KF!{Rzwlzz|DVuy8+Qch%#;13 zi`d;D?u(kw+z#05SvbF^v4JQ4Pzhfq_ll`uC+PGYGoFC2BebCD46gDC?NP>m^*n6F zwAe%tnTc+ngc4!lw z6RZ3!VboTHwY%(Jt-`s*Rjeg|{$cHY{*~Lo>mLTC@0G&Us*{@Y<`Lb^=?#j}n&upS z*U!V013_*!2j@C}wc$GF@Sq|z{QE2ac)|YhmyZmzbiDeih;+P4=k45xp}0-IRQbUY z=5BsVNuBK@8H#bow8Xm&z?19rttzCmc=-1>hhR;vgMa0_7oO|YBRJ!A`)To1js|~k zI-M&KImZ(%`(AyOXKaBTyzf=`X!PY612TYJf6v=I<$-Q9Ee}fgFf`EOT8OXBcc%RG&)32d_Hg@uu+^&&~_YaqBu1 zyB6!*{LZlTX|z7*qZ0|&cr++Zp3nr&;M?y$z~W^vMGvG|~acM)p zNNwDV6_CF``8e-+>z4F$@XpZl;8V%xh)v}hQl83jT7L{V_*dVd0y&8|Dstu1WbLD$ z^7f8uE!1{Jh=&(aya4y}D2OTE>Ox;S$F|?<+-2PkU7|P-cHF@`4rr)*za!icL7v<4 z^NxZMGF0XRhRe^J5SLiIj0r)qb0t1Wc0Rxaoe9;x#l%gOUi(dvZICwTM^y zsxsX+EE!)6jM>>|7gjNMKILu3oOT|2W^SMev1&Yb3+FMrgPtR1UD!F-jZ_7(_Wr4e zA<(@H$Y)IF1(0!hi!om(D?9L|?{KT^hxoTzwjDCqI5YT~Bu>HPLS&8;6qt>R-n?uJFsU(hqPmoWF{K4o0T44gH~ zy<*&2oZFZ-qu05wN)`e$bhUYS$mzcXbSXI=sGb6d28en%Q_+VR3q0}xj-$e zgWOY%Zw`%dJ>>Tqb)uNFjOGI@kY#i7XgsB?1ALibY_UtGD00j-@Vn;Jp)T@ug%2b& z`=LU`j(mXgqHa)(f-HO&vY3J25i>*Hr-#nc^2ocdii`rPH&xxl#W=r&`%N+-A0v|$ zhc$hHKccd!9XI3bah1Be`ey8{p}8BY75jVFD*?oiox8rE*^#SJ-`g~b=Vhwmk#Wo} z=~TtnO5kIjPQ)J`*Dv|dh#mK2WU${YK;GOpze1Rhc{uCq);?QdxAfuM`=~tUSl?*7 z=C%sA_Ikzk_v8HC>k8>NoNunMt$PrQb%VCHkcDl%7kWMjJsY&G_YoHceL!k!*H!nr z##zWU4d(~Jm+#Nd<%newtai&u=A1Bc+}b|q60zgfEZ3M&!I7_o zJpQbVOBRe}d@O1a1Z1+fhViE^MSa>o0w&1i?DtWphWh%PPQ~tree%`@#2ZO(+yfZ| zdvI0%8P}X&Vf%1y+&l{Sj|T19uT;n$P3V0yVL#H*V1jV z|3WAB>SkMUh zL3i3%u_k$r0R9QtO367B!`j^ow4bH1p)X$?(wE*EKa+l*)R*#k@ap9ACx`T<_debK z8pBzEYXe2AuSLwOJWzhw6r2^9g0lisa8{rUX9db|R-g>+WoR!!ZCMFw%SsR%gM31q zu^BvOnne_I(wZVHo^2Ef)ZT`h4J95mui>~0mCr&B|DFTa#P8Zx9DY2aa07Q+n25zz z<#}gL%WS))ASXxGyhi3$3A4<`eHq8aJm@ycx7U+>NuM}}9EHzG_cmC)Ow5CxqxN}` zgbA0l=MI70p;T>rog=pe+bokLr3X0Q!0u}9T<(5luFsTJ0vtOa_B*BV>s9mrL@ zyBv3~9MHqaccE5Yjn^83@YirAcM@}r+zPsrLW}!g_o^!D3Yh!eos7S=k=b?}_g=U- z9}Ky=1?Pm=@v324fF98;r>u zd?V^6!43g#O#MUHC7_cI%nw^4+Mdvkz?RO(-Y!8bV%|0n4hwhmY{7T$K`XOW?B%fLQkp5@zD!Y(ug#e`%`9&?y_%#L6Vs#$#o@utgRxAsEUnltHM z4%|&VpY5*cWA3g3#MZlU2j^&o)*m0cf52G}zY?+WxY;rm{D_=R6WK^q!}T`krcY2T zYf%ewP~aV!|J3#eWKP1Yex2558^?o`cL3~+_yP8*PPv}&6=V%kbl}Th%&?=@ zfYV{~$KU+oY087kJv2>bO-L7X9=n)W#aJM`sOAs3L(_UI+<_rW*1{eMJL z9$-LzZM`voS~KJ{fbYVlInMhxe~a*HuV0`D<58UdM2>FVZ)dn>l@f06LEH^_CD=0Y zXftwjc!oSQomnA!gU%?ET?hH0CHeG^;JsN>%`aAfu5mw_IX%A4|33Knopbp4nD-2^ zHBa7u3G(6a$ag{?c+Vyz-wA#3e7O*$u^}spQu^rz;&EC#a_pyJ2OJBR>xYSc#i+Jp zBCD-UWVgM|b7s6Qa)AGpeP5z{DEt%HqE}*%^%(Z;8m$3)oZM5~{UB@FoJD)FpWwfT zd*|^_U4eSBEfsvjD293m#SNjhHe~t24Ve39qhw$4z5hyxP%F+$h7-==u!XTdM6ELJ zliaTGQF@H#2nR+nKJY1TuIVQeh{rJ3{uY~>6;^EfZqV}g6!-re)FFQfabWALvu4yn zlHYt(2=oj3szJTOJqNMpK_wot`l+5-K3jCqgZ07QuLue2jtaqM9CkxHVAsARVby-7 zF%9t2Itfk@eg%Aa_n@=rZqqR>9rS)!;0|r~do9QmpxVa#_wTgQP@Zzje zd~?fLrs98wI&(4G4Tnxd}Pu zn0>*(gw7$k8Q=J|{~|d9+465r*Ugih>gRlJ^jYM3p9_*aAp6gg385{3)kHnC4jHfU zXg~a-XOY7}od(`RJxfw{uqR0$I0wH-u>kb%PdE?MmD8Fuk~zzuW5*ghF_wZF7frsq z_lt_t^ElT0Bh<=_g->xaYV)VyEZ_nqQ25Vu=fSmFv2rbPsZ&rRFaBOX%3u;q(kcTS}kRY4u_X3}{FllKRfby=z-+> zSErr}1F>}3r}aLs&G?6*wn(at-J2Zm)2TMEPv~Eg<6SZGIlEih-)7~-1QXd{GLJ9k z3Et)PiA+rOAw82E@0-+*>?PD>{vLh=a@UBBd9wGBbenMue#@w|Z^G84+hQNWZ$VqC zU$8daX6W!E^2LyE5{jnVP|p!Hc-l8^x9H5Y+dNJ8F}Zou?1dRB_C=V!hLX_*A}^Gs4b1Js^ok*=eM=qL~9dfBys*8 zz+W3$+p-+28@2vhk~!GmvUD5b7ST%7HKp1@-%7W2X9CZ-cOli*dVjjD#1DL#={9y> zy~HDEG+Jqp?Uu~<&LtSRS&6e2I_Lzo9&Zr+2CIg>k37xL`!}VZ$H14V=fSVheqihm z(_^rIO1}%6dg$HISHL?@qyFJm)IZ#c80M|W^?V(n7y!DqV-HNsn^&z5D*)n0(VW@gOCIRNN2eId^T|5w6S`)1w3_@c>Q7pOY{ z?v?n%9k*)m+iYVKzIS`R+uS@>HV^qC_-{X1v40g78fWD9L-NKPZ1@+KdZDW`Zm-OE_{jLW2a7J%}{5Fv> z0XFBKg0Piwx5>We;lpi(54ROIQX^>8^VhsPN^am)$T^hcVc)t@H~B)4>N#M0?h0Hz z@#lfhZhaoQV8_Tl!I`{6Kfh1W&bGjW$6gFvzV$`S^Ww-p3^sdP8&CO)a_-g&vf~5A zTVD%I+}h^MB$=-_QvGW(e(-aQ^YdZf2^PdAhT8v)*Cl<)x*=b(4f?>CY6MfhBKeYS z$?=|}_dQ?oKH1I}BL172)2qq<-O!xg_cw;-^uE82_G1Elus(nCUcVVyX>}j`t~Ozi z?#F%_pgGv=@l&y@oHYi1+W<0v`~tK37;KOirOgiCKl}{*oy(!uS0c`6%^LE#rs7Uz zx4aNOm#NsepG!n%LZ9^xKu2Q?_zBUD>jdgtQoaJ_e~s?qb`~|K=ROgenDiGgXLZ|o z{=zzAOv>N-Oa20EF~ch+?l53QlB`UM&v_2tjU@7psOwzW>ahV)gf>Yuxj0~eTM z@6a65hod>jhr=i8<2+pH2Z{n)Vt@f>F{d5gg*u?*xRdZqf6-0)hJ463w3NTfH`F_> zmgB;w2^4K5x>Hhq6X7g=F!lk(nn6FW3((*&db!MdHssHQKvQpzd?$3N_YD4wl*OnI zH1xwG-@%<+@)`UYPhLL^8ax)hRtL`*l<#=jIsBZb_aS$kyP8(wjAH}NMmBKNZHK>5 z9S={@-wsc$ehqa%Te&u)jgJEUr#;qywIB}NxPoefiH2i!{pO3x3!sPG!_-ox9! z!4cbVO~7l-c$@ao_5t3I=?htPGvD)JXb%Y9s0Xh`@esgE z@es)$xU)RPmnpcZ4$(d0^Z0W!;9X-afe-UMUySvUZ+uT#(uXno2|oF3Q5k$^*x{!d z7YM>FYBz<|_8MZ-fc0(QHVrGqVa|hVr|LT4c)JP9;}FU z5UeC;;)RIcth1nd3AdAQo)NX-$Ci1pGP9rHlg}2dfUOL?_CNO(zUeB7SKE38{w#31 z9+%`i1OJKU1x_W8!ykz2g$d`5LePL;m-IRer{V2s8X%m0EDaD&b?fFp`OVM;GN(j$ zN%l*ad`~RJnZ_3=-=keyz18;Lr34t!J7PhHAIB$h00WJcJPSOSqG4kO|=l96rwBFcq7Qo8JKTB_U$diX$)CQP4P8J&%@$t!{b9z-v9np@@dBm zmuJpzUmYEuR^8yd7AthtLsye*22BX)Lb}VD=#XM;f2$mI*1t1{;1TE@QxEbsNb{ z8?j$r6HB-TXeQc4_hjUL6wNvxbY+uF1W#;rtLdH{)RCBv;%?pQr(F|y&``7Pn$LN6 z6UZ1{`=IT|cifY~XCfyb$-{4Oy$CpHPvK`vdndHr=~<83z@VS}alpLQyR#eofOl|D z3TnYJQ}-Khb(a6AED*vyHd+7R)phr+hfE2Xa-E0PTN?U@OZ2A$I~tKkiztE3CFFO1 z9e(%M;dkE(zx!7B-M7H+z6E~wLipVa;dd{9-@O2S_k8%>^Wk^TgYR$~`Q34!ah%o{ zKehf$0el;r>%s4b;1hSN@n{yS-$H&&=sN`wYKxUX2TT8)&y0M|9!S1F6bDF-e;+-s#~=KZ&%nRC zD(%Cyiga7a)$s4GOt-O(>9%F~ohIXobX)MzbXyaCgQRj&x-GPU+JK+HIq-ecdtQ0@ z$mgLYglo^Qi@k$+#z{ZlqwTfnHiLd=VXTY~$Tn7+Zj1dN)`d322Rz#)nr_3{w`lA# z86S{spF~c{<6cI!m#RGf2YZap6gUsRVA2_@r0kkVzn#Vnz;*GbS-~cPFKXK6WF@==Iu8Di z9X$+tMwfOx`~%hYJu_s#ll{P}V84&H28Y}4&bp4v0~5Akjj*$K?4;i^;(YnH5wA4U zb02TKMEY5nTjV3>hC)<~H%NXo<;|p>H4nBR?(j*^e{{tB(uSq^H<}~ok9Le7K0jZ! zmU30;xd$8b$seM1(>!IphMWif#%+J|TBHTk zetgoMyk7j#z}Yaf2=y{U@tgJZZ+Rz|$79H|%k!ZM*UO9K| zAC2=(h@Et>Kw&4@8UxNf`$top!L3I8M}3rP`{}ozEIW)ke&k;$he^L#7&mVkbZZaF z-}FF?3-@)7W`WRrzK|&tc8@F|Wu%NeVGBGyB zhh2ejy)o9}eLu#A504lb{SL}>=l2IBZ95PB2Jp{7UYh)akoRl}-SuCBy#bC2I|x7T zOL=J-G7mvDn1b#R@a%)rUR&%poOpOdTWhbRTNA$ng0|%QJuP{Ply4%^_`Wcsr`@JT zx>pK(-_EqjraBHue^FP-#^s|11LqL`I~b(-uqm*3%UADxaa)&+w ztYJg*V1S-4>dI=sGl80p0G>H__xN3NOOS7lXf1iUxuT~OdZ!Zp-u|FV@l_MQMY;kx z^U{N;n}}hpohafyDW|BG-Rz0>TK*K$mau>_)TNjy!hLNzn5rj&~p(( zjUVnBq;-p)5{A2!AkR^oBhT(4cWOd5>@_eS=oNSp50rt{^AT?VJprfAIu+v-u=pi? zbhcc+FM3Pi>seXI<>B7SF4Xy;&Uanoz)U%iO? zP-pie>tZpl24i=@A23iq*~J<{s8xzi23~TNaq}%D{7hvc{B$ItHN+CsA9cXW69;|p zQ#A#(z{(SEs)~CQclmNn8F!PWxbNMB+F(nuc-B2#($^1fuat47z|*v@DEdYalLAhdHBqhyaS4h;kv|R? zE+-tw8V2B;<`LEe;GqU{pNofD;Gvdzcvu5Gtif+95FWz7Ll`wfga^>fUxkM}4-ZSa z4#W4#kb45$b94WQeF>}v?xLmG8%8i)U~g&}U`p=I8U~n>dlP1WDY-W_?5~5V#DnSX zu6MLOpvygZOxrsN^jQL3QpvPes&HOyG0u!F1C4rgL+~}M&R4WO*rz=>r@OZi?}Lxm z%w-L0mass0Ico^FE8&-8=#O*5uXLh+x5RUx8e>#rKO-0;l8^Wv_BD!rQS_@pznXT1 zWH`|^&V;}DaWK(7p9>eSiJk|GHzw%8XQ}6oDPvY^W}Y{Wh=LDSOh%0i;Gy5D0RIzD zr}~4gp$8`q^}{_l^1XPrIY7S)5ePL)*;l{%P(rN!wOOXX22+$^Qr}*Ke|z_g6#oSJ zb2Y1%ddj#cQ2rCdHGUy|v4Z7f^W2ZRuvjBEmp?908<@=J?vlT6KIF4SsNVFMw4D=r zKC{R>|BgFh|DEposc#}ZSo!a~XBlKl2)QaY!Hu>Dd8sFN?B$3l8O@MA^$BO76S^F@ zofdoPkvy!q$&hRD?7blJE0G5IyTX_s`D7Ufq3{s~& z=J@fj_J&7F01NOycm{q>qy7`WMX=gLeJAb!zRW=VCv2+IL^u9K5jqmfkqp2dvhXDzlqKfwjYBWsKj}97A}LFz*$4Y3SsyC z0_*)Xd?E#R3;z!1)cy!t?9Yf_{RHvz->C)50F&9>MteYZ5@JoM{QgroYoU5DL^krI ztu61p8;$rJ?x-HRZ*fGw;E$*_mCoM7Ry4I@#f1HCz7tFi!Rt#^z_KP#vu2Tca2e>-=WX1S%d5syl}tNJt4Gz z5o1MxOZSAlvJPvJXAA4U%21OUOn5vK`aPbHxSK~*LzftDB%BZGa3&u6S%UA?6Hzap zhx;w+bPk`^Szf0jo(tF&$bak^Xz)m=b+T3hToxL-Rlb>6?kzlLEQY%f6$XE(pT-K8fJZ|z*FH%5;{7{x7UO-S-yxPmzdvr~i@A_9 zxTl)Vn`kZ88tefpz`x=5uI4LO;Jj6ciE9c`L*}cXb6s|ys@T?1j@mg5N5q zdq1293v&WHtT5zVKG%a-8}_37kDza?`K~B_vxD%4wN=lMd=hRyoNyj9M~B-_C7eg` zS-Ki_6zU3BzO7RHJlx)v2=CdKuzj#6A@>68AmWOBQclqr@%y55mO+zevmwjqtec1D zU?<%}Of`jC8GN3S)pXbJ8H$^FFcHrwz!`j@QnZ(@hTjEUQXB)k&>bJ)Ljjl4XDT4N zF{C_NDCH5pLmu5q;}6LrJgb+_>u!NOx=qTP9ddteC7!OYgG?|C)H55C1CYfe2MQLa z`c!_6M=LQN z?hW@9Y{z~VTaJ?t`ozC^^`1M$iU%Q^u;1tYHhpysay9!<>r|69^xO0U_-*>~-a8!= zIehQ|V$<-sXb!UZp}*j3d9~NUd34_j$uB2c*M-3VON4wZgX%oAow0=kL%}w{php+- z<$%Eg3}yN7CH4gAzCFA52(xwA7bal1BkChPLiVcjP?s5KjxCJm>;2yTVjr=Gw4c~V z1@i6u_ylm7+`sFF?O*UC_U|8o@9T%{Uy$}9+5g&M{il6I|EcJI-LU@Cus>3s(A~H7 zQLGvM9CX8U=~I=OY$-EQdj|PxV*jB(0{Ty+E~GnjA?r4H`U1LP3HqAbt`_EMCFxII zN3sOtOBtdyM`S+@_Zk!J;BMV7a`TXsH}V~ZTFmp`nFT-WW8RrGgJL&BbI~}HD%0>z z90BkCk?{8LVer~RV?gGOfCW4vA|0p~367lSJa{A5p0}nF=vTrW^e*uh*%2P@X5ud2 zUxPMMxHIRZVQIbUBVm!ait)Ch(PfLW(pg`tm=Xc{GqYV-AjqTyvxW=8hYn~v=)*^4_`L-A`<*rLn>YG!=UXtF*DQnmUXyUfw3q^Pf#3a1 zw3L7Lv-L}1gMO3Y4CkIjTDfl#?v8j*Y@~Cq^AXeQV4AD4@Gs%#P3MaHGR{kcao#WP z;Edd*`2@{;gsTFqz?)j$j%DSNXfqd**zE!`2H@>hYb!p1oz`> z&h`6svYWLQ%mtYTe|(kapZr?tNN!dgllJgX?u~s&bfpy|r;wC=9JWTF2zp*u;DgY; zo0Z@8#(<9ldX%!0Y_kZ?C7ApFBz+ti!wbHT+%Dk8TF)6%t6WXCy^7o=_yqB9x+_Q0 zc4a>|C&0cl<$b^0z&@YTSB$VZD^DeH5hq&@F#icYM}DAabv}HKG4MI^;B({!iYoFD z8|H`&bHs)@+Bw?ESGx#j&MqR`GkLb@)5v3Cy-K!oxRKqP8=S*U1-T;FBb)L7i;@kQ zp5xq;zes$W>PJJ~yN^AKcSAS8PeHynmpzgPKfILs;oU>AyRi<~MHut{A?|$OswlPx zzI*pxxWMI)f`E#;1R5qH|3O8?0>d(;6tkoR0fj;!#D8UV5im7N6#wwl3KL7qN=wUE zR@f7>o+Xx+^?a#mJu6>fsacu)&di>HyXW3Dt@ru-wq);q_sp4dW@cw+W@l%)oOGk3 zT$PYJd8i!pImp@59Oa<>rRh8U)ojoQ{hM}ua8K=sw+iJ>oH_?-Z+DQh4|9}Lk~MuN zPFXxaAAF0YUEdH#xhf%dx(lp3Vt0_U57NoSqP~+^-9R6V^|tFvc9c`%Q0`bkIOubb zvnM#pRkh2_hyr~U2Yqpla>`HJM*MaZ2#bOY#verdaXQI2xTFp(}_ zjRAcQa`t|Xa#ihe=O%(ac-OUEACw`7c;hvFP~NO3zFjc|bUMhU_Hikj46-LzRDfRi z){@X`hxKM%=#5`$%{#k-l|SeQ+a2Xqm-5l=@=#VK4+s4{T*||Do;3YZ80dG9mtuAD zgET+$&SuG_eo_MH_UzDITjnSWePmvi!;)`x&pX>2VISrbF0c1lE{FN1$?JXN z+5DM6C0-7!im&VfWxY$)z{&t+kQ@Nd4*lWTp+7u3>)5AVYaPsEp)QM*rDGlxG(y6?N{46uxFQ%J+;K12(afhCwsEm?Rn6_o-WKDWrQnx zYV+#s&=1CY=ZTe@7K1%w+4Ij1n+_P*WO+nylUpws^L)|RrmTt%o0`0M8o9K|Zz8ve z^}+F8ed5VY)umF)NcKEdZ`*OrHa_mC%fAQpwvFfl>D6d#+lqTSY?EN^14yqMU8Ps% zZNj!XHfAH*2+KA>d%9&9dsggh;~4`REz|Wjx_LqRtv0qXE2qQ8rk{EGxwdhn&c;WW zo!CZMw&^_NZ-W1$Fn86Zt+F@29-Py&P;cu9(Am7i*wz(U9kxpU<>{H>Dn0#DsjYSH z@ElyUm7d&m8tlEU&I{W2hBkLHu-S5#-e$LRkiON%HfP<`VRO@Qp1v+^u1$1l^8#i! zw%t~4g6CH)J^dHMdkdGf{Z@mrk$!8t?Fqd8`3BN^wz2IihIZI4eZpk#% zXN5TkqD{Ga)8}A+=eou4eCH2+$Tjf6lCJl`?cb38#l}8l!JI=;hc>;(%ghZfeYoaw zKGe-)eqft-^`;gmKW_fs&`-W1U+y#TB^}n*!25xgA1#m{lZ<^?(YwPJ=}n#=E`6yD z{zG3Bcu!Zf%~x*P1O4_nb&tWjsaNdNE~D$CpWY|8e?b1+X6#cIj8nAd&r3XiM!U)% zKc6e{sjiCog?))9H^Fzho9>12A?50PJ7C~jdJnyCBep|+r5XFS!n4CS>1m!{E`7^X zuGBYWD6DxS`asJzZ2|w_J--96UfI?9c-+88i?7~Cw`U>$5{-S#g0X}4{Hx>nH^x=| zrOv(@AFGB|S|A^_KHRcRjZi+vK>G;RulzHosI2j?J@28tB3r&*4Wn-@Xc1? zt5n1D)1|M{w5#=1878xQ)%urDZdwWcriMkIasRVE^LB3ZI)i$rxmEA?o(1q6HrUwj zE?;oJb67jnK7;$6Ug-(#SgUheRLcD`zE=%{Z^w4@uNQ&;(SOZ<_#O-OAHJ&tQ)i$Z z-h7Ps592cF(Eldw@GQ~p?ed|6{{`*-C%f`LHS5p&k7EYao7B={y?*~|{zKo(*#8#d ze0OI%j1c z^IsbSsovxV{_@CbHf3z$An}+;(|8Y#G8pb4#^*Z6t z-Z|+4Ya?2qo{C=Q6K1~EcfA?n#Uhe!y{`^=@Z;!rW!w_3oW~!>qUZtheU+ zgn8WOv)*HuZ@wbiB z=1?_D8`huZeHhjsU~OvF9%XGf)|T^tHDVX}K%dMP%Fh}1Ra*Vsm0xR1;JWmI>(d9W zQ`Tl;*Ce!Yd3&8*tI%J9aceWo3xGKsvW2BBPyd_r_x2Nh+rNjh`ljY*=oR?cyio7w zh)`%>Y;p1v#z(X;Ai^XdO!C-zu!`0?B^lg@27s&fuH^!;3KR< z?eFCSb8rq=^nTip3O{)p7<{c$;5r3g>*ig7pEv9M%(`Ir^zn_FT1Y^aAGg@0zvPk#?xejea{!Z)6{pN~Vn zRzbdkuT`-!d^-y2B*;_t4uh-wtRnfD*K>PC>9M2pG(YdV0zcD->;2qw81l2w*v~`o zzM)obg`fTlH9zaT6v)T>I{ehvx9@0vf?upp1AbP;!TT-XEBDh1W%zP_(){eay}0z4 z@6Vc_OSSg><*(0Jy`LlAhx~-~Uv}xooYULu+g`%YI>^tkWSDcg2>mo`ezN-tE4ThO zU4CxU{IqF)!hJ>a6Z~cQ32Vs0ct5OPVUV9`q}&E>pImxu%y*ifl~LFfk;re9x>2E_n_4&C$m!Cf1FUwE3KDBZS{(+xWNtG_ktul)E z*=_rT(ql`GYJTGV^YZ!GMepZ`7a%`VjQz}ld4yWI6@H3x%dSseZqd&$*1v9VCrGQ9 zp9*W6^KvWv#Oo8v?PdKW_s_h*?UAL&_J54!_Db>-`o50!(4HqDKckHOJoJ;3pQ7B_ zG(W>&jD(LL==`)VaP(7QeG-0sg1-*s)+j%#obxjkuFt)ipTn=f&*lqyKS$I;e)cl< zGYjT*lKezJ!=iI}emeP?$)6wH@5)al4(5Pffu9O#CqR9h2-oLM&Ci%C@H72ey`Ot3 zAwN4A`+4XS>SrC+x0muW7hxg^m#LV zaBXz-75_?~rOp%H6KoyxxBr>GMclsS|2uu$z9s)VeXwS6>zGCVGku;mrmyCIrf(6~ zXaAq+^Mv-8hkQ3vzaOIv*x3Vn6(Y!=dUfjDOU zaQ2K5*dvaN_08)RG44B`@+#=F*Lhmu+>&Zn=U9Kf4(ia-*8TI0&a?i09lRe1GWN^K zurYx;xUWK+`_doDv9Sa8JsR-+;+4pi?We1W zON@ckEn;Dx`r*%n72_u`=fVSYwEQ(4GU%AJ@2}~oguY_0y?;%I3_6bfo85LlHUEASk| z#OJ7TdwcH@_6i?i?Xw@@S%W{D`&kF^!g@^*XEn6l%`m5F9gLB(xFOzTnDfov4di-i z-U*9`c$2q6+{ZzN`7Pp3Erj%iw4!krz!LKqdRf>|R}-)0rv&q`w7J0+m@8$0xl(4BE5+WKb7S+M zF7H$G3qs$Co^0JY$1-CdclACsZ!-4DKITM-<*c($8#V|V>T1%sPbY#cKVIJM^ruCb z6P+!sdb_2OS8sRvlg4&SX|RUJx6XF=hW9K*85*bA9b)#NeGq&5Fd?LW|g|poo9v3#$)#Ph-`&o`$-tP2AMHpCn8pdWE%ZbF^x4+7=pZ^a><+NB7~0LBAvZrP!a(`nr?=bQ=c?@1^gUo~w>=cf_a2?y zJPfQg*2=7 zZ?|N=db`tMU1y_vlGFy}yV2S1-Y}m|*u71Z@24+sck`_x43ux^ck0sn!qwZ|e2cN& z_Mf19*E`$2VWhC3u4cC=-zzU~clrns2I_C-M4DJ?VYk z{{Ge5-Q3IAZhJGVKc>IWYxOt011Qql4DS^|TRhlu>hgA{!#p~)yR+qMlHPA$z1`^n z#&%1uL;L!ei}Z#ubzygaW_QSC?(^FH%_hP?`}1?X-S$_m-tK0rvEB9;A^#6L+r0sv z$qT!~HM{*RAN@gk!}>9p-rX!PXTb5glr~6e|fu`-xXn?e0SXEc|7)#tGB!PAI5gui=ceFxX*8RTi8%nQ!UE(;>+8ezEgyO z@(ttBSf6O=lXvxYr|&SfTe=&{ceRW3-X?5-_O~eC9rt-yYezSRqt)NAJ^_|*c>jrw zd+KdZy&c9^uDq|tb=GV)wmtPWSTB@~OI~nc|3+a;T}`8AKbM_!PNcp6!fi5?3m1N* zH;S;R|3|$aO*dV=AC?AVKbq3Dc%J&s*^dotge_sPPAuBtzl{9@(f*?@>|Y{mf%dsWJ{;}n^SjIg%VH5u(|zJn6db2Unj{ZNU&j)%RQeh0>DtzENYg~^3a34}bwRn2H ztMh?}>+LWOaMHntNgZPWE`6w(uFr=_yYxOt-LBq;^it!pBz3|3e%;xJukI1H)K#Aa zA7K1iyZ#-=1WG1>SdsbsSa}nDSEH-0D_jneyJT*tG9RHsCmV&2xF*!{VcW}b(&tY9svJ@9_z?IU1rUJ$Hb1#51=diiWE4F0`NOD8GL zaxT^1y*Ia~4)O!m1%I&)@{X--yGon8-~;})ud~(>*L@h5CHczY%5@P}`m_4DQr#Wn z@`p83VeKNGC$K&kynnn>@gF~5iL*4rICmFFgP+^#EHTn6@NIgwmVX_SXUC8HCpFIf zD|jxz{DFVq3tI~X{gEBxz%^%J9g+DmTYCl91A%Xv!Wy-()~f&b^Ea?H0#}WI=N{TR zNxL1_NrF5#T(1w-&QSbeo#3k1VGR*jKUmoYzyH1npAFT(^P3#7%?xD<<`{%^7 zY>g_g&*i#!@Jx<E>*=7Zy!HT+!qKI3y6pq-a$5UvK^y@)nA z_f@m8&gQ+aMvg(a8aUU)*SS&B`)bd@0xaerR&FhpaF$;zEkwGU2)2B$BrJk;gFKL^#;(4uf@fMvf~-B)Vm8-o zXz%;O`IDLr%|TkZ6L|}DO6yZ!I_FseZ)>n}2l;ve=BtK)O(C%6MYpiz(C)AXOZTwo z;oYGeb%ixpx`xHy*A>oph4VpRa}Ye23-Y(Xx=u}ej!`50Rv6rz{cMdEe+#b7 zGP`CR)WbgPy6}Rv0^zxlPZIoQ>#FDFZ<1bv-$D0C@Lf%h043r5g)kuke{cuenJoThBMI{F6apL*HKj<#{wbr-OHu z*0D7zY;~SxFz*)P_k#SjwfeGWiEM40Aa-r`f$Pg1=FwOzPx1VyNr&&8uY-BXd)}?9 z4qW0N^fP=ja~7-}#NOqu^z!%kr7g~~0lq2Q1M0N|xHqly&a-;JdWh99uV41bYh5(R zYfX138}K_P1)fF9Udj;JcB1nOY&^_sRWyH}>OEMi{kJgNeX#yX478K)3xv3BAS;8- zFu$`B_&Ohm56a0pSocHrhV!saz*b*4=g;Oy)xq_u>1yf@a{g5#<$x2OD}I4`ITq$K zc_|~8dV$Sy9Xw|ZONn9YY1ovkP+L`(;WlM_uB~ePIxpq+U0zkUANNuwKpL%pbvc9F z<+@d{K2)$(iTi2;thE5&?nuP$m%P;$76~?XS?68VCD&UCs`Rc38t$zGhkA$g z++_>va@;K}aGhIN&@Q*IP6yn=I?L{1{%7360^q$3v+Q06<;CAkGO>CF*K8|*_1-;z zE1bi1qj4!eOp0+|FNH$7$dKNUW?OigJqYj0fgKQEwCu;yItuAgBvmSJ0<}_k2eB&u8mH zR{CRIHZ+L!^(<@+$@E0Nh9H-#fi;I5){q3Ih0jWY@B<+aL|vHd5I)u+e7r&UI0z5x z6t#zshdgP2ze*Wj835NofD*JTpepEiKvjCD0A)gGK-Gld0adr<2C(aat&vt&Zk zbb;#yt{o+Cmv>m;0iUp-<33@*XMDoCf?T()K4IN=`7qyt65(GGOC$EKmgUwuw>_i% z-5(jtuK87|{5lA5^a1Mk3;vLHS~-?pWWQN@_dC}`V*0dnw2XjtH8WuCRx`d2)LWBl zFaOWwNp7YpXv?wnmh+zc8p;`zUnuYFn_(vc+@OE2trHwq^K~lAcedr_mgVLZRm@RK zXBL!CDK4GWWE!M4Nq+D%x1y+Is#;cBR8pblG|4%VU+(nj1?3e*r6p=kalw=dwaHH{ zFPd6dk)uw@Eh;X^hmangs>;r3Klxdv&nvGmw>&qmqM%$;)g*gL#YL0LbIa!p$Sp1| z%^NViJa531X%$iB(_O?9q>smS96pl^rWTc`DMQqPl6*Cy$;^H>`Sn$26&94J(~FDp zm_N)DuxIj|iUPH$B)?#`+SErany!|VR;aluGgF;hI-?{XEE}vARj^YwJZuz|$=QhAO7XRhdVB9!a!DPhmt!4Wf|Bc_0B9Wg>>Q07Ue-Pg#xJ+Ky^xKxtdox zZ5m`;lZ5#TNz9Uw=j!x9YDHlIOKz6dO`UlhjA%uHF=zW{loaKa<`)bogZL|QCl?nu zCWOw*$wgB!ue(eum{wXoN9F0HnaHvdoZ=-&GgtB}&n=l+z{@L^#cNoJVCHIPm_J(j z0K!7jB>5JVK=CQc*9s9_UtW=F!R)dExW4io9O%d+{)<`NSyRiCSrq>(ic;izySs3$ ziY#|J=Q6|d%X6oemM|kcAQ=m$imE_&DF(7^(Pdc2h1MhwV*fkmk7IOLOs}%2mlfw$ zKvGZRg}r>n^omL4ye4w#S$@%+NxXVwzC{0|@_JPJD@h@61l6px(@P`4@SAP$NgBTS zd8>Tigy*;6@xiki@5awcQlbeyCIi2deKbz>Z0n@)d_Qe3^gs~ZCgV{C%H^_4WLjL$JOPXX%b-*0s8=%SJ-(a}*n1}Zlm(%}l?o0dBpEO!yl{Se;UrM;od;G*f1 z3Z|7+%!%mBV|TXmHQgHX6QnL(*vnhNJxN$fKYLv6$70QYZv7+5K_y z9QFQ!a_F$IZF<3dGYU%b3U0n*e)1>H)8g&8NwT($y>m^&fE{U)SreBse^mLe?s$AV zrd!YR8V^OzQkh*B)!`c7{1^A*`e=Go+*5rS2As+F6AS@{DZ}Sk6Q~KLj7R=;MOJ>%fwz z3t2c(e~NueqROx|F)AwRt|3E0hd`Z{S6DE;`8SQfi~IL*55~{7f3|7mU!3C!+j7tiOBWaW&Kr@V|?CrW9(@a=7fGovWad(#fSz zU(RwqlV3Eo2--y{YJ7B5lmy??P-L^o;_hy;T0Kmj7B7>J*-!3d>TK~336Q&(f=pe# zLo7Y4z2tED9`n7X64Oh{R?|+?e$xTdLE9mZPfVYhK9`SKj+?%g|6@L7`d)1{Uoib@ z`AxQ6J9y~mF-x9&@~HgMi|IArMfpIQ!>1A-Hi#^3(%b1%O1X2P+~ zk1TxrNwc?4r_Oz2;s>RV7&+t_id*F+7tHX`eZhIQ*3pWXPv z>pOS5dD*)37&I*X)@PpG_d$bu*KXJJ9y;vke@_3<*1X58hV||f5tlqDE0*Ve6wYM z+0)&_JypHdZ1YG|23fkfn{DoyBa`C14>_*LuwGx_;<&Zi6kJZnwJ0@HJVB*Bw?D)_3=hu{>D@D|W4%YZdycnGxW>oRZG>kJ<;IaoiVs9Q5OhbH zJ?-bax(`-*WXZm<-c@U+%J@W>-UuVvC>*G1X zGs5Cuxn+=j&qPanx{d{b`W{tbXkArOP&Lef^E*J@38$#mTSQBs0Gxk_HVPGV-Rosvn1w+g^WT z&-)+lKlzo^e!&c8SIph{1=UN}Jn`O#`@K8$9W*$7vGmb+pO@$^uvio0S`6vbw?C|)oy(#0~`y}SGE?j}pHEz^91 z(jRKLPHw)oLFOL4C#loS_w=^!wanY1baR{cyK;wnphvI=D{}Y1h0@LK4)=bR5uTA| zC=^PJSERX{o0nqW45vl~*w0#16klbiCE41~GOw*uuysJE{>n8zp}zLT=6S0Fy}B$| zZW&-14CO1>!~WJa6*l`P-75Vo_TwHuKB**mRAvX*cUbNJ4oFcv-IA>%tTwj_ub#@C z<~uy>Rly;ifgYpG_C;>bH`;>CG3(5gpZ9UMSuFEjQLl4@6OWngZz?H95q)!1==$cW zIipKU3UajGAcSSx(e!RZl>Obl-u2tQOYHdlJ*(dhx>WZ3k>3vT<1t5ezIAcythV#N z9pT5ePwpN5!_x6@b-H+xAE#V=xb}r!EssTBJk5`*R%gXTWZ(Mnh>K_W@%Hzgd11-s z`<}?Xc#$9f^U?3aW?i%P+XpV1+gNvi9qX;r#gBLGyb5v!>!x>Gw!}e0J5_t3KF2zoGl@ z@%;F!&DRChd&d8e@OuhBe*EQx>wcS>{Bq{+Y5aKbust6gJ-D~}-rq;@ z+4JSFzXi1I(*&mzV)k}54D}<$NLs!mU`^lx%h8wXZdktLDw%Q1ig0Pm9~rgnB}=7rLO(3O|WT&+9_%B=H~Bazo5Wc)NHHvSbkylz+sg=d5;YZ?cY4#nEcV9X;M5tPQPY#P@ikZJhebd;m6nhw)9Ap6~X!^^OeBy2pLj|I*{G-9Jj%{CL8Dx<39@zK7M?3Z0G|&-5FS4X*$S{2SxWhDPGpZg@Y%*!O(*$rO4_rHpUqwKTZ`#5KlV#&e0J2RnQwdtYlpL~+uGDue|Y@) zN8OZ*{5Z1u_GkQl=+&Ys@X-p``o=8%=Bq}(HG>r!KYqftcHM7l{Qi>#YmW2tX9rLI zOpVxFriAe0n*Gn-fA`I4_D7X)e%$}xo0Zg)p>JwzRtkteyIJ6FlT#;fL>7 zy!MHpxPza=Lk)Jksr!j-%l_5%$#Y5?KmKgi(br4fUiqD`c@#f((WH)=mJ1`>&=6{^-%5!`Qa*ky@9(*$5iA-X#oE#NnTj)C}&r(D|zO>D_#yf z9CT7Wvw*X>C};iU&Mx>A;B5Sh%CoEb8W-FbxGQ^n3^**S=u&=`0iSKaA28tW0B7Zc z+W#9cSALnmPFLx0zk&Wa$RQYf!4t+e;om6*?!DJaQp0>%O1<7!vahU{q~qr-()+6i z?<)OqJ{t?I{9$v=#NpHWe{Y6yieC4;o&VqDlK-xH_Vcs94EshI6D-L?S44UI?Wpp5 zau?qLCo95EpWFYj^@w@*=UYD5+4bSLXOup@z8MX5h&(r{e&Qn^zg7O!XNMmd(53U9 z%rEXOE4gXE@8K1PO745P&z32BUIgH*ZqoYi=0CTjbS?S|pGpS~i8!Uyz%z$2#$yBe%-m*K3PBHCCmE?bfO3Gt$ zjw-nonIyC9shToP(ANgbyP7QWDpR-4-f|ynS1(zPRHDH*FcQY0Zh*8mnQY+M067j4 zz+|$3=hvC6^7ky^WEd{<^YfEH)0grJc!&*tnj@e!u>s;34qsNd#chOFjQIgM(YG)7 z>Z!zlUUzwj5^j;LLuH#O-UCw2Y?3D_CNm_A{DiDnyYST2a>B=5vD_d-BC!IYn87(8 zQitG~Mq82yz3;A&X9ypd7?oEJ_gg?B*-k6h(smrz8(E-wLG) zQXt9{Bv}+UtJUP*)4W`flFYGI*+&kv$i9+04D&IqmVCJZ!VED>=1ZoZn0iQi$$gr; zlw)s&3kK?dDzhprwd6>5`8P61M6;=J`bHB9b0$Di(iILJbm(bcFU>UyHx4>yIbXlC&37EOmu8?Ty%VNLUdwu zQgm|kz?kTmn3&j@xS05ugqXybq?qKGfw9rCF|o0+ak25S39*T>NwLYX1LLCOV&Y=s z;^N}t65af z7?>EH7?T*A7?&8In2?y5n3R~DI4~(XDJCg4DK05KDIqB_DJdyAX<%}6a!hh;a$ItJ zazb)qa#C_~^1y*$;y{RgAgCS)!3HwKDt)rC`j%}?3sk;8yinV3S)}dRBhK=Y++yt! z+8}tu3&+rfpHTwO&EWYuJVk~F)%gXV;{A67*P=Z?WcQ2o+in|k+aUE8c-lV=2GH?o za>4Apf`a^l{7AK|ymV?gJb(kO&~|_)cO_G!Jg+oT&~Fs)27C@9?1=|iW{=a<1+_4j zO`0g_&z||Hg)j|7d$bL*Y@>Px0b}>OaZ6PAD@i#^wS8@^w!eUTGw%1|`Q&BV`4l|1 z<8d*{W#jQN)SH1k0QpYj2a(s~aU<&E^FVUT%VBOs2|Nqsvof?%7VURQ!K{ioWd-bc z=Zw6HX}M)6R$c_12XS&{E6&nUD{qODlkhGDR>o;{Jl`bMvoDK&G~-uFIA^O4fLK!k-E1^*&{ywtV;_AbI? z&@jm$W@rB(Ofa;ASeR@PPn~7C+X{Cco018)%hYTZ-Ny$HX)%U?_)hqjefCmYIP4*; zUj_@yLcqq(AAx^4a6Xa&a-R8p5&jj!c{4i?8>>6~AfuShOqOA;?NO}692PDEDCD6Pr>=+U^|?5eT^(2 zg%YkxrtcVpO;y_3SUy5nwY?m9DyNuVj z;1_JHETlr1*$}3dfi#~?r*dz~w3#wH$~_ZfWob5qYk_bfTH2+y+lA-r;ru?gwzeEN zW_lgZhXdLH=WXt7ZIPN^erXG2&$(K9D~DzFL#vaHft;U5TiaPk2NymmJ0XW1ohk&e z0O;Da*xK5%wJ>(Mq9Y+#rKFX$zj>{;t?|~%i5Zd-#2m`W=l|03UWqU|rS*O75Lc6L zTN^AL%j~nuWkzxFm`tZwL}iWRb}dZ+ z77i>K%Qv}}6bbBgEO#vIVy35CTl>9$G3YZ%k-$X#%h)zx@xa*i$F@=MZ!fTMj6rz^ zU$*>F{(35fyl!*KU??%n{$MNAJw4mn_QG$_m+E|7F8~KRuImU88wFwZL70;)%ml}} zrqIg-;#k>e*FVTs_iAfPWwMU-5*#vL>*0JOoagsN$GR2I?|}1b;rw2$d~A^&DhL+- zFq}`jrmc;o4YS|jG}nIt&X>V?R=>JB9}JDn1#td?cD|PCPloe3VNkDX=R4|tIA-y~ zs~-HkEB&nO&4%-{A^bKiysNSY)vd1Vjnf@NxD5E$1bR+_p4uzDu7ly`=;FF&<;n&F zauIzx%3lgF6<8!NcHe|_IwrepphbXEIE9r3ulYcnmCqaqe;{gq%*R%cZ3Wp> zCJP(OA2T#yL;AI~)oVUF-@}v%;2*h(LAXr#mkMEL_lNtGR)2St15dc`wcqFU2fP8< zan7{QK~e>s%Ry%~ytBo81K&GzvSZj-`Pl(73qZyS^*SrRIrO%n-I#W>Y9y2UyYhAgjH<-Rm&=-*c<(dx``)qOl!+WRI6SBzN zNM8f!TRgI@t-+Vucg*V#_3iV5vgqYXAFJ0|LEn)HZEf(00p_o&@7E|zkW8v$$0ilT z!oio#6XCkR@=-|By1nTMZTw8i{=a9__#{?1c0e5ch0SH@tKK zuTikK1!AHG#z#f>&o6-C|4~IH_ZE~7Qb&zSQ)6SIVxp4Oh{B4Bvgv~c41h^@g)=5c z!5akwn1cSrFkOE@aWQ}KqVyh^ZyyB`YIJmdY+Qa!bbelZa$e%($piBfk|yU4Ow5nZ zg)yr9eaf2HoMO+0RlwGcmp>wk&4SwAixfN%v2KH$P&^ zsP!GrFn7(;8HZ=?+PUt02WPFS2JmlBzPCtSbySi<`LVN}aNw@=59ji-WF`8waUy3v z66N<1`OyaaR^;P6RQ^l+8E?SvK)!{@7a-qB_&%gN;ZM5b%hj{rwO#>f!fu2aZ@e$L;Bm7yJV1X~Oj6V+U}O&6{WGEVz)*HsF(hGke5) zDUBFlC&~*h^z1U=yOGoPP~J1(`;hPSR)uQ5KMb6ep9xqVL``U7_ZJ5)0$DhB&R;9% z&iM+(+`bymR_|2I&Kj-P+^rgAsIxikNW`uSmBQ z$i;h2+WkqArhtA|=~>0&m8Ae5RhZ8A3k>+9oICsVIOop!zLaxkzu@VbOMA8gXV-;z z|4Lk^9{fiK7smP+@J`56h+lyQyesk$Uwu0CMjkrHCf$}Gb{3eudL3v^A$0&b_$R9=djGr}0QBFKqdmAjZ`Uwr}80I)34<=*C*HDZ9-C@;9s^PmB@b8eDEc@Xkd$VEO1J|DR#4}vd5 zF5dSOd@*v7zk)A8F49NvWt=--zbiO*zJA&Gm8*Jt4RBZW$qobkZy4x*%RtW;26~Pg z=s9ViM`ry&$j1qtRraHOgXNT9bLJk%{qVg=5ugj_CaDn1o8UcBUc6r^co=f={-xj% z$i;h?g7-%*-p>>~7P)v|Q}86@jl|9yknbdX4Dus{Pek5I_*CSz0jh|S@23m>gxiIF z!XHDP+(oZvHS$ctpFuv3@RyMn6aE(RGQ!{I+&RBKK=}nk{v!i^2zhFt-u^F9e=R8w z-=VyCk5(jJEAj@S=NxkJeyx!I6}fm1SMWCE;=NqK%~tkHmJSmAosgdt<&i$7mcS8FR`mLf}q4hsuz7BBKFBAE~yFU>5*T_Xa zitF^+iJH8~cfnKPApp}O@`ZQXLC-woB7cSce;^n6EA*J}()5V(d<`Zu|4&r{=fCl+Y(&81@OE~H=dAV*k_5uzeq#fis4L9J|BHu^k z;vz|l_+9Tp!#JMaT zBla&b;LDJQbXSE6zJC&VGU3l5w}t5CUqxO<_&dnA5WXKcOV0&pzsUDrP<|hgx7e6j zvUG~@PRPwY^!D^Xt`goCc?#hP$R`j!9C-!dBMkURxLN3x-@M6xL%V#O)&gHY5bLaB82Chd|Uy1U@=iopj_vE_fGeD24 z^1O`em!-AD-&F>DHS(QA{u$(l34a;66sn3O;QP0bhYoG*N`t&8zJ1)h(&>PNc)ca_dzT;5rKAI_cgy|01(NCW*NxjfXj z#NW{d{8r>gi2Pm1PZC~)T)IY;9Jd+Bg9*RifIrB&NfPVP2wm)XBdb>%NWEIcxpTVB z=iE8n7IN-@*h308o*dy+zi$Ra8eB1<_jU%OntK4)xe+zzn&ExIh z{3QJO&VYZ9ybSdS`CmDQ_9{sS#fM4A?d$ajc`I_UZjRvI$WIadU6HGOR3XauJ&}ub zZN$ki@T zF;qRuFYl*u#L^Q6ya9PblwN*=0pEx`e1Kkl8*p}?4gO8zsgkyRf$}ZU8b>UhFyLP! zFOJj8e`mnIM=sJq=>N%ppGV$==_cfVGvJqyi*dpVqsN>bU6_RSx; zop2TTTEhDa{e%xfZcSF(b+aGC3^=^T2b(OZME*tteiQN(B0t7}--bMc$WKC^O?WYI zR!$~hIk7PFU|WUqWki0h0e?#H6qSb;e>S831*l)td!M5G0wRAB<;#e?uOHJ0&z*^U zfB_FeUOYq3GETr*B2;1DpfE4E%I@MpGTfexTzD1N0y2S z_d&jy@b1W42#-L1nD7MT(r~?<*CP)hd^GY1!tX>rf$%BF%Lu>MfR`X&OynOxzLD?+ z$afO{m;tXvewN6uFyQsb{jOIf$87^}mhUZ?@8bIUFUkiH`Cn1~6p>Hs%(TLDPa=OS z@=U_-Mn0SHdy&@?J{x&G;Wfw`2w#T$AmL9TKTUX}0e=>`?FQ8`*`&<|{3Xsiu4@tK zW#r=e5_~)If1c6n-vONEi&$UKgaJ;Vyx>C5*C;R6Ar$hR{F#JF5?sg!0B8EedWHP) z3Y;8<@`4Nb>ye9cB6vD-Q62=(;M}?XznOFA`hPU%&h`JTz+KhDC0ri*5hP!x8}OOP z=MwoU&P`Go=|{{*d9e(vxpCET9{4?ZM!jB;LAp9tDKf=F6o=W&v$P2Lk z5$SV^bLaB*9p}#F?R(Ch%Uf$6To=&)74ga#!ROF^U|gh+;N1%}F49L_ciG5=U(u-N zN#r8^h5S+EBHe`k=ZiG`A|HkPY2+gPg?#^eGu7Id1Kd$uv3&b_hO9;JG*0P8Hrrj*$w#z$c3Ffko!*4^oaE7 zg?t~_t*~X~MjP`A+0lx=%1(BbLd@kYhke?;|apV^XUyXdit!le1?8h_6 zn+SgydB|;g`L}?x{4F$vay{a@K85n}ME)%DQG`oDnjSmRa~*JYCY#77a&D5gk@{*N za=+j8cBUXdN%%12N80rA*CUU>H&vJwY)eO;CTsp`6yCW)F4j{O{AT1LeFPtkT=*;a zt;p*!9RweTypizRId?A4cXIArp6}w^xjZk&`ctICD2(_MT{9) zqTag`xk&$msAny5k#5>5i<0yOa*;3Wy#ltWrJ8<`4mJ%-?1RQE-sjJ$oLG@RgIuJK zsAqD(Usu=TgFGEz{DG9Kc?P@&xt+)_15Ax9jzsLOrM4H9a91Z|AP;hb)uS5B2BL5W1HxT*vQGP9v-*3P_LO$UR6;oK-9Yt=N zsOP7FGrxj8_2nmsHx!|rc9&j09C6VE4D^UJ0k*`Gg zQzV@?qkJoo|2xX(pnMYQKZ){ZiToLquP6FLc)~)v=x%*J_65%TU4Z`fNB!ea-jB%V zqWlh$K8sO4g2?|3VZfQc(M11f zlwV8aC!%}?k)Mz9+lYJ}=O$_PFZy&|iSql1{2BxPB=XiAy`JZh7v}2u4&5) zKH(oBpG){rkUy$!3+^v@cn=G9q+#fhg|Jh#p`e7)_OZVvQzZrQ5;S-Rn zgcqQGiRiCI`D7yh1o9NZpF=&tM9(3VA4lZBL_UG=A5c#;(bJ8)DNAKU{#xV}gvSGC z>2{dtnS}C-iF`5gTEgd`o+hHF5#=`$`K`z|6aE(R-Gu)W^=~Bl&!hYiBCqgbAWIhr z_d_0VFApe*tq1aG!mmR?}q3Y9c=u`2xZhB5xpkCGtkX*CXFa z_!i_%gujXWFyZebKSKDY$j=gf61hz)7$P~PGr(Co)RJ@vxrT{AyOGHEMV>-ECtTuwPX7knzek}iSnn3{Cmi)>;iGv zK1Hq){uS~R!hb?Oj&M1QDTRIz;l9YL2@gTOmhisF8wgKCzJu^I$kw1?-n{Wj> zAWV;yl#?jlF@bR>B0m`UY{D~8k4p4RNBLSJZ%4kI@W)Wk7NTbd%5Ns}&B(V9{t@b_ zCwhKI`MpHmv$s}0_Yuy%RnO8VndrG5C0eyM62YEE%vw^dCGfBMb zQ9gsnZ$+L%_}j>56aE46TEhQ@d?VqfkT(&29yqhJkk}d8M@!GcL_P|6E8&BYTj%Q2 zCj+@k_$>xJ6L}7izZ>}x!i$mbdr%+m{lJ-Dsowm?!PiP-9yOu7-$Q!&4^h4q)4|Gw zVe`M1{gtI?A|DEz>A!&TV%%v8%4ZV!3Y0gaJ@8n8Z+}PmG9v#j$_Jx-1j>8!A24o1 zAQ#+Vy&70cYvig#HGj zqNh>bR;icYg7O=Q{J&5>g2;b^^0h=hpf8IE+NET?GzhsEM`BWJ>xNvc^RH1!>VaI0 zBMGh|7vn{Ohanf^LW1`}F2;WZ?~7cF^9UY^T#UB}J^;BGPZK;AxfuTuJOQ~F=Mg*^ zxfl--d@yn`?jiV4VRa?y_vd=_%i&lUWBt7T(rXlUxQq%)4^GnX1?L0FH z(hZ)w348Wp?2k>+xUk0$`F`ZW9!zGb(^O6V!mlcq6!Kp|yspy0)Q^cd+i&6A*?uc< zS9*FI=!r1U)6YOphJl`&4fKpQ&~vYWo)QB+_ZjGU+(6G#13k+P^lUZIv&}%yYX*7_ z8tD1dK+op}dVV(0^Q(cL-wpJ1i*#LndT{PsepKMD%Fhr3J*ftIZZOc3W1uI`K+hBd zJyiyJ<{Ri)XrSjA13jAz^lUcJ^PYj8eFl2=8|XQ0pyvkzJwF=g@$K(A-#c^eobO$L zyUO=C13sMVk)?Wae@QctzYXP=KcX_j+PAw6crNnIL_Qz+PQuH8v*+pi7N}geP1d3~ zit_u2{CB|FeJ}#=7tv@@mnilF-bW+yp~zba?+={mnSgqDHw`r0j`C-Td>+c%QC{>1 zA47Q?+K=W)waEPlUyD41@QuiG2;YXhjPNGp)r5b5d;#H~BX1!5-^d#Y{}%a1!hc5I zMEI}BMLvpj_#OELBJVkXNyt*jLRE7ES-wex9g^JJtnE1wD)Er-$(cy z?)kzXM4^Eh`-pBm1c)8|MQlulEJ{Z@=%%y`B-?2kvj6uGb;t1;>ia(f#2+DBEi zMBDv{z5Z(`YFyTqaqY1wOc|74`kY^A+ z5&0;>ry|cMyaIV4;g!g139m-JgYc!ucN6|3@|4H*>GM4D48nIH-$HmZ@+QJRLVl3& zqsR{vej0fz;lCi4mgwzti)9%N@97ink35)gm2-H`_={do81mvD^}G*qKYx8a(-(OJ z;gQHE5I%r&=lUU*bLaYD)qQY(Ve7Hr^|F(>3EQZ0jf;G5z>1*PbnUtpeu?@d2f6TT zpr%Gzhg|q2>W43p3%~lJd{~91U-%{D^O0}(QRR}NK1l$-T-7JH8Kgs&K{`w@&~rbR zhvyU|e;-7iLij??VV)Stmt`m~zJG}BN~@4(6FuvZ&nEmO#k0|UpgM2U1a|!hfK|Q`0pl=-e0p*9tM-WYLzenW@(GekZXxwKRjCi4AI8(_Y(dh@`HrG0i3m~ z{g$iT6zwlePfcKlvUHZn2O<~W73G28Pj}?%GF2eHj{wfnAqLaIhG)m3y!fuE2s8nC z8qrgLdL)vbwJ0yXe=78>Kwe1nJdIp@KUK&-i+nMW-v*r7A3*Fs%H^Hww=YqT_eBlj}X2Gc`M-`Bey-N zxAPeC*@XWWxt;J|kuN9QeGv0ombMTcfIR#ueY~N_BMFZ}o=W&&s_BYX?;3G4LnzKJ}C@b{5d5dJChTEb5v z4}V&({|xd-!Y?6DCERPU1RK1+Nq8{w3xxMZF0I$c8;d-E@L|ZK2_J?0AmMi)KSKBv z+ha$*gYd_YHxa%X`9Z>;MczvIHsp;P^zrUOzM1e3kv9?kFXTrEKZShl zGkX2!kT();N|9iLbutO}MShU*5aes0)$8wzypixkp`Y*@gnq&^h5n6t{dWodgx@3d z6Fy7mC%jtd-=x>SROl!CNui(c=Y@X4cL+Vt>Gkgc&hB?Pc)#l>X81?6%e8BT65^XmPc?jY6BabHh5#*x?UyeL{vtIu?at4Az!{#AMfYL8wo#!d?(@Oksl`9JWPU3mgc^!*WVfWV!~DAjf6)bZz4Pe zdHySU{Wl@6AbbMy#e`2mzLD?>$$M)+Rj z*@S#3Ta1)r$wP}(N*o#Z*3 z?cuo(kq<^5{kEzJ;@>{ViwTcM-az>E$WIZTi9Do9um5i3nS>W3Zy@}B-iJzhx|0*J&~(>_4*@` zk0X2#@N^0S1eA&>Y# zum3jW*@WjH-%NN3@?(V0MIP{>UjHKG`GnUauP6K&$XG2wy8n+Oj_ewOf9 zbC1wZ_-y2J37?O=h4AIbtsm?4KaD(<@GZ!f6aE(ReT45rZa%2j|2gsrgr7oQOZa)@ zdkHs>kYI!PW{33pJ0l-QxQcu+;Zevh5T1fO9@{@GHn!b_JcsZJ$VGcela{23$hQ&s zBILGDRUyjvvyi6|UW0r#;dRKj5WWt1%3;0!M&PV{I10J;J#2{jMizYsXGd&PkmnOU zoj8Z_aPqvM8_Lfm^1YC6A-q3uHV&{C#{t~5Xr&1#f0oGKg5&5qb`yd?br*j7T0qao{`5@%u2=5J? zrB4d_<&SzYQ9l3wy1VkA$*!v2F@X$_Kv={?LB3cKQY>BX-nR>CX3IWHX0l9T;N|sO zzOQHc`?}NJ-^_dw3lz)J60M*?0i%L~M%lEAE~wLmv#Er*V6y0roXX9 ze}~4oRM+QHU7tsE`ul6?Kc?vq)aZ|D97p3^q;Z~pop?B}^KdQwrJBCyvuiq~`gpOX zJ2kqe>1S*7eVYEp8vUrG&+GGXpo{+UfKLAcUHUgPj-i`MJ+A2w*6_cr=?~ZF=Up#y zLcjamnt_m?&(iceYxEat`a?DP%QXG{HF~V+e^H}fqv;RV=(lM4r@uh!lWF>%M=AYo zO~158f1Rekpho{CpbLF|Oxq2kKkw7&y;}Oe()0s0`o}f>M2-GsO~127|5r_)*682T z^q;NKpK*f_1MI7>(J#~V`)l-BjCE`qwqx*fB%@7fm;I+t9x$>GSL3Pe}Uw`uM*Cy=fi%hi(*zaL%G8 z_m^1cFO~H9a$h0o^W{2{K7ao1rcJPiuusyI>*$8LkiMy&ud$SyTFT8W<*r-sf5n3T zW()pXEcm}+!T)Ou{s%4ik67^k)`I_E7W{8n@H>YD!{_C4KG2)^-<9d-<<2C1UhbX+ zKeXWYEck^5f5U=*%7XuE7W}tb@b9!T-1g|JxS)^9~C+&h!5Q zNuQVRg+OnTFPG`(Dczi+`GSn!7y{I^-~f762hb_@RRTJS$&!T*>A z{}UGcPg(H4=ZKKwJpZ2}>GSg4BkA+pf}0)M=bb1 zYQewCg1_H_zh%L{+k!u};GePJ|BeO!T^9TYEckzD!T+QM|1%c+&s*>xwctPfre^tG zEa~&|y+qRI<@;QqH_7+MEckmZ_y;Wb*I4k!7W{1s{#gtDPg?MQ&w~F47W_Z5;Qy%w z|FahSFIe!uWWoOj3;r{YHOu$el0Glr=Slj!e7_IqP4eAm!9Qrhzt)0(g9ZPz1%Jna z|5^+F>n!;1w&4G<1^+!3{6Dkcf6;>fWefgSE%^Uv!GF&2X8C@vq|eLuQc0he?+*aI zNxoNG@UOGr-)O-_|B40wYZm;+Ecjoy z;6MN7X8B$w>GSe^fuzsN_eDT|4vd#Od)5SCXOH~b>73B?M=oBI6ggc9Pfxu?r5`*) z(XWudb~7Sa-#(%1@2d0l%~H*mwS=Mx%dv1{-MiN`nx*n-^NcUy19qnxlqv`(sXlg?c1NF z=uf#*rN8pBHA%P^L?r%=UZd#u9b1#%_dG>@bpBk^%{}1{UaaUBCMvzT2jf2!xpPF* zANu|^Nx4$f-Mdu!(cU#lk;83xI(3(#oA*}VdA|I)^KMO_zHm(v)-)gfS<~zMd}*q1 zE?QIR@0GdWen?HfU(?NdOkUYj>CO9FuhQwiuIc9e>@U~l_A-_JRX@EZQ{H)=%J873 zoA>+NrR#rrsnVPGR^P92j;|}ad7rYG-+r^EoA)Mr3cm9}O*ii~_Ow3#x2Bu-!(OV> zzidO{oA(ZXK+|8X>E`{yU)A(CY5Eg;*CfTr@k5$!-Y5G3UH@+x9IYo;YMj^hRk`Ng zlDjm0cv8{L`xzh9^oKRwyjSsFjsN;nD!qB%+~b=5ivvYB?{Rxv^Z&%AqI);4N#v_E z{yz;nooB=Rt+@yC60OgCq|%%FOE1v!It%nmz;4v=yZFN zNvE3)H#dtd@q2%go$jX7>A2t9o)+-aWM^}l_TY14G99ZY_1Q_&!RE=~U?<%iuJ@@0SLRlwH_Ro9|!l{ zkW@@ajvYRIVsb~aFyrCrK0nd9RT=ZODL1G7ZR7s5V9puwkz^a`_&ZoktV)5FRfWt1 zYa}BiF9j2U5Sd^4X_2{U-YY?zpua3&S?POmR(3(nrH(HZiBJ)vKe!n4j5T{s+6#J+ z&>@9eRb)YG?>nv-rZ%%aOS%!%*0fmkU&&<8^?KZQveHY-ICs*ZES#(tx^5Wpw3nrD z9l$J?=;`fp)%$q6T-ZtoYtSy&>h?!U->n`*cs8wB) zq^)XK)fiOZ|4-kolz#qUK{xPqukGzji_PuqRF~&Y7Q4Nk7eZ%etf!rm0u@%X>j!?p zoy>Q_(hKrlrcwyquFFDb(DgT8=Op?^nPTpb=>^#1V2_5q64qp_X-pUu12pfh%rCYM zh;zGwBlB%xqG)IgYu6Y~iXv6T?PR#2oFv1|=D6Q;Vju|sZU@78m=J~R6=4*nS(#;N zFDhM@JD!^sshc}J=7nzIm0jt=4a4A`i`MyYd0cR-WqDpR!`;d%F0HaFYH6xWzhH&o zf~74hg@wc`>$kinSnRI&(ylxg%T#`8nGZ|cC0~R%T7pQGpEnz;QWjVT95Wh0Rosb+ zG;~-m%^)6Tc^vi%2#Xyz49hr6bBA{sjV%_GBjbhn&WojjIgJ^HJJQUFWXvnWGE0Lv z;8B?ID0aQP=X)+oQzy-%E{4ELgS#*8*SMEpwH1n5x1Z9g8KU~E$z%a5L_sDmX1RH` z@c~y5^8`17Rvg!9L4{;LS7{fdYT^T~5-r*^5my187vKld=^wHL;hu=O!_8v4G0Z0! z3yMjWj*27~0Y@T7jEy{PaB`T__9G?4LziP}c^*N@*dYEYHHY?D=8H$}lS2!jHl*XHE_(ACz7f z3&o(=K24h#Rxs+Hu{@<`T8f1gQF`Kb^_CvhfL9f(+`!UyOAB7*6Fs11xxx~da@A)| zLu+3bD6A;eK$)skrjxVS4Ko&T2IDd>3S2)(y&_Iar|{!6cIAM<4|GEI`YVcKavs~<(xCujQ8Y@-V^H-n-pyIRxK zKs-vf`q?QM^0PRdOp5U|DbxO-5WQ@x7z0iPDtPdufRe!-jlwWLWJp$(j=9b-+erW_ zLq@|6^;s!kTO9z_LY~&CgOyTK2e0b3pihWao90xkum$c|fuw#^IfOpU!8BE+VitZ_ zP(R%LO=(z$I3B@$3kMUV+D#S38R<9z!$a(Zl(nWVxHQoNNroFgsgAoe8%tWXxxq zT(JA9JSEFR?q^QyhfWyu{0K(NId^>+C>MDMf4jt{VF}sIW=qD4`qbM&1dZfuD;T#M z>xJNf^aMRG5Pl=favqj05Aq@}LsrBv&M#B9?7=MGOq;MWRUBH1fOEydNVNQKfli8M zHL*rEDP?}>`gxv)VGpL%Vh84;8Hg?|dN9)#iYDP2EGR~Bsa^~gYa~NU5m{QIOLuE~ zGb{&F4m~1*dDj#Iww)j!r|ZKl|LBq1h^rJfL^h!4v6u&0?sMNQGL{8FoTkvddcD{$ z^T_XlQByJFszv+ju)eX)f>H*Os$(X@(Uf_k;bhY94R(_8aC=KwePhL{$YW`(FlU7B zwrdO44k6Zdxv=A_ba`nF3A-x=UY-qG2GP^n)sa{RS#-;MgputzNesW}wk?Zm(sDU- zVpL!@t+A9H|<>g_oIh(*-o)33W zxX=_a7kkUutln}&tnpIJ?KmwbDl5rK=Q{7PJS=_>x7ouXr-$p{VFT-9dHNX5$7p_g z2j*eT@-YWp3@>MP+i}9hHKAVwd`l2g6C%qMdMU|=`6yf6t|nA6nEzgTCrJg5+vedq zhJtl1tA#CBfQ1-fxdpha0J9*(0R9S0#UKIZM}QFntk3~gi2%1az^WeNX25GCX1&=b zzqF4RJOYBN1h?)Zcu}Qxe0NEO1*_{}DP!%KN&0h)Im;YeLFQl%G6z=zHg=$Idb*Y#}D3|9J}T4aVX2g@$QpSMySA#lesRC#DWH! ztwC5`gMM$b>vBJJSqR%jc$5d6nGHZH;esSgm%bp0+3>d@iP^2NAc@hu1xZZn79^2N z7|^H%NzB~gf+W%MMw@9+I|{g~W!#0BYiW|@+yzg#6lFPg!DlLz;i%X;z1b~-(s6Ux zGaB?btShH_Q`zSBWRPqYo0DSN&BWGcL&!!uK$!IbXgzG9K8q+~U$5A^$NKhF@?**+ z?u!y%F6S{ve!vo5IgF2r1-|Rx3APjlNqC??fepYrVpHM%$;qP|oBaCe&|SYh2~-nM z(ZYF43z)`Un6jwM%G`0HIC9g#=dicgb%KDGIqPE2j)R!WYA;2=5qA}kEzJd5iFt)1 zG7>bRMv=G%N2EfnFc_W21Z}Ac1~;0-PBb9E6@kHukml`b+Ps1Lygv-&)@axOYF{Lh zDe&fLvBU)Rd(yD=j%m;ljXcv(@auvTbE_FjdteEyEXJ@mBU#^uWvXs3%fiBQdl{^@ zBBXmjQjAvC~bt4SOS9P8__NG6cLV=BQ@2xewnk@2OpYA|>&-HeB!pZQ+dOL+z>onZv~L}61f zgXJdKWSY4ewJyyp=Oswy*-XXq%zAV*tM;7PqR`@JN)bxgu9TMO+{l`W)|hp%=2)SLtV~S6*wsakG&yXYk;VyW*f-@ z7#SCmVc~2^ZE02HT$N!k88Obrbjv|z4i{pmP|4jQPgtx5*{2B$ZtG7s4ye5xM~AT6 zaDgwz@f3@191c&xW<{EJAM+A*-U+$YOgikD2ElN%(QYmvVn^2P!5M~_d8rSsGxt4X zF;_klCW4NJxWt!g?}BSr$5RgOpRC`#byF{jcJA=*Nf^hK5z0{&+yDkajyEpSeDB6d z?j%d0W=yL3RGH>}loz2J1YYdtVk-umB`QkTSzTs%0J~E}QlmW7AG8Rk4`_kg6(u@& zc2s23B0qQ|=+s3TRjs|TG0#HB9`WDx+a zLHjsi22eLH=ocJYtzu&g59SR=^$X^|{Vat%ol)h%G9Zf+F6IGQ<|C^jauv&<(RC^u zlaa}HGKo%Buof&`V*MxU9%K%i%!>QC24pgfOsV;p2XZOPv_~$4nlE&f40l1ga)qTp z<|yeh7S;p%nigGi!#p4hTx#M{I@qO_1h-aAakk5cE6iqYZ)tg0kI1TFh&dHvS;>V= z!}t01p6VAo9*~PT=9l@End%ojCXvf6)i1aPat)>W1vfpy{3EMWWQBn&S5>J6k^nw+-5TS4XcP*jDR_=MS;1B7UrV!1+EstkeMeDiw-Tq|BY1& z!01Hobp3|x?O?>!FydaAi+c+r4u%mA!-$Jv#K$n=WMEzcbAfEIV8qWb;%MNMB*}-3 z2ct`jWXX>aZ^MYYVZ`4s;&2%8IE=U)*w~8eLYxjGUWXC41Bdo;KH_*7*}1`p>tV$A zFtV+K5%0sumI_Av4Gc88PmRSa(LuJ1kA$_K{V3Ml3udCZ5UF_o_EW z#JUkH&&X0aOp4(0$Ot6ee#0(@$ra?P4aDR#viXA1 z-512_!$C|`0$lSzzG1#_vNMB|of({L7=bA(f`Vnl$z~ExHj{8NXyL@_b7J*5vHF|@ z@SM!&abop3vHDz2NEr^o(I{MN8pac=&xzINboU~$`kYvOPPYuwXdb2vh`Ht@aOY$a zfs<_loETd!2GVLK{KUkCvDwlAEf{=1F_$jb=iI9ap?W=qQo=l>KRYg8u~hEIYZop` z8IpM%E=_gI+`>B7atq~cnOo>P?QR%ZC>clE9U_*te$7}avX>hRxSr3veomLO%jl^CEpxyfh(5- zG2rTXcEh*blw-D=tiS_^&sJ^^#Fwk)5z*bsd8%D4?b{>bztziGT|OczTe%zvY*x;r zJe|tcQm;9TWLGW+jP1&Kz_72LXBT{fao)=1z-VywJiCz3E^HNtk>kpBgAv~9d3M1A z7z3_e&g%Bsg`)$jmgDZiR=Kd>f8}x@DqT4b%mS^P2LiY%kBDXWPx6De?i{=Qp8nAZ zPr@Wg#@mx=#smG7$cx$%SWX;{lZ|vMhqyup!M2RP$e0f-`NWxexJQP|0DAsT%W#~Y zNlq8pbr38^5G)@{&)f>%#QhedgW*_2%cl#@@?oN%6R44{mKZ?7ny|hc^P0i1mktgB zLDp7`7VX6`u3Dy=DKi|JcuVRCrTMgquuG-C)t_u6>*L{>ePPla3}B-nOci==;JI*p zjUPmCiIkY760AQYN4<;cCD;IWbSf@v9E=2RGTbTvTeV7FA{yOs!sv)0U3+lv(d6in<6TEr)PWfuIMMCF&cVR(U{e-E$_Z=+ z?f?dCf9%Mp6>j45gTgO*ncFMFBFLd}Io!+RgeixeU~xBCfYuHnJZFUHoDtYUrhxPs z=O1Qww5aW!ZFDb$>zvZ8Kix@&urv?XNt{`bOKCTYw7#OwS!J5LuX0u?^^}NPDun{- z&5iT@f?h4VU{A%|W(nBcD3BYOBSx^kya!6AIWZCYWEX&os|j2fJD-GJ5R>h&N)vP5 z^I->X2=`4BqxVmgJKhcBW_#pTOx3+M@I4}Fa(z>%{B}*R9i%u|EU!K6YzC=OY4`i)x0Jd~{Fl8=O5>5f= zTZKSI3obxGw?;4@?o%++SZh~i#H~6@;u=fDT^G6wt%j%X?11}_)y)}( z#}!z^VGw-z2MhB)+z~#}x8n#ww&bial}(&!CmU_9cMlNTWz(((+S>2F2HH~W9>6`< zCU|y$)?GP*t}O3DO5mD4xLIsrZ#L#dW{_R^9QwiBg)f!f+B`&4r!t*@R8530aGay9 zHZNkMvTO}K3E6z6Y<@P}noPNiz9f17bkf^N?kUDY*}6lMvYiLqVNN1^hq~!aRS;IE zodA~kyvU0p*j)*$xsmoQa3ZdBQ(s)1Sj0WJq`QP0?vTC0~pE!1AEC+^{yz?JYtc1pKr@%@m#^?pd1{lp|{$BxbUfIw9H#3XN* zf5(=;XqW$NbN)k* z3)n0l@-*_|6e4?As1DrNDZAS4!eT0X^*{q;m=rm%@KNmwT@X$(m)t|RvvUwuIJ77i z9)eOkxABHt810#ii*}a4cF$_dH|*!!cQz66j>&AZ6kx^t43rfvk%Ezy-r@&VXCC;Y!Y~t35>!LiFUosSO@S0bC*+!yW~pam%iGCEXaz0)(~t*4I24 zrQ_*jWfacT^{_P@ZRi*r?u1*IU0AD&A{R!bumUT+`qGx_ps}f;?ErKK**$=(^&5W^8~I7#GZ0bIk` zt>%lsOU91)19yrBa3KOLm`T-GicrmU?HWOACkq-7cFT%LaAGt(!&|mOyN|{?wBv)B z_-$&1mJ*f?h#D9d=8ahW=Z25YO#nFqIU^pv?*lMT#25O<@@*U zzxLn(SO^k#{q6=xPrAgqrwSBtWFI_mvMyKQp#Q>nr5IlU6#a`ZjHADO4G!g7Tc<`Rwi9j^3Gq=-eZhiUvJ7DNUL1!U=GeUeHvfy0 z3Ce(<j$Rs-Si{ z_v!b6%P;V!p8qmU)2}1$Jf`2*{@8O>{(AcQ_aB7(BBcZW<9{aq&tW1wE7aNNOMnJt z!&{c=zpdw~lrN>^D!(De@L<|*XyWrNI{&5jE9%qWV?PMV)Ze@hdN0sT+f_>S_dV}X fiPc{sv);t literal 0 HcmV?d00001 diff --git a/patches/openvm-sdk/programs/examples/verify-stark.rs b/patches/openvm-sdk/programs/examples/verify-stark.rs new file mode 100644 index 00000000..48436033 --- /dev/null +++ b/patches/openvm-sdk/programs/examples/verify-stark.rs @@ -0,0 +1,30 @@ +#![cfg_attr( + all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), + no_main +)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::vec::Vec; + +use openvm::io::read; +use openvm_deferral_guest::Commit; +use openvm_verify_stark_guest::{verify_stark, ProofOutput}; + +openvm::entry!(main); + +pub fn main() { + let app_exe_commit: Commit = read(); + let app_vm_commit: Commit = read(); + let user_public_values: Vec = read(); + + let expected = ProofOutput { + app_exe_commit, + app_vm_commit, + user_public_values, + }; + + let input_commit: Commit = read(); + verify_stark::<0>(&input_commit, &expected); +} diff --git a/patches/openvm-sdk/src/builder.rs b/patches/openvm-sdk/src/builder.rs new file mode 100644 index 00000000..fd8d2a95 --- /dev/null +++ b/patches/openvm-sdk/src/builder.rs @@ -0,0 +1,562 @@ +use std::{ + marker::PhantomData, + sync::{Arc, OnceLock}, +}; + +use eyre::eyre; +use openvm_circuit::arch::{VmBuilder, VmExecutionConfig, VmExecutor}; +use openvm_sdk_config::TranspilerConfig; +use openvm_stark_backend::StarkEngine; +use openvm_transpiler::transpiler::Transpiler; +#[cfg(feature = "evm-prove")] +use { + crate::{ + config::Halo2Config, halo2_params::CacheHalo2ParamsReader, keygen::Halo2ProvingKey, + prover::Halo2Prover, + }, + openvm_static_verifier::StaticVerifierShape, + std::path::Path, +}; +#[cfg(feature = "root-prover")] +use { + crate::{keygen::RootProvingKey, prover::RootProver}, + openvm_stark_backend::SystemParams, + openvm_stark_sdk::config::root_params_with_100_bits_security, +}; + +use crate::{ + config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}, + keygen::{AggProvingKey, AppProvingKey}, + prover::{AggProver, DeferralPathProver, DeferralProver}, + GenericSdk, SdkError, F, SC, +}; + +enum AppSource { + Config(AppConfig), + Pk(AppProvingKey), +} + +#[allow(clippy::large_enum_variant)] +enum AggSource { + Params(AggregationSystemParams), + Pk(AggProvingKey), +} + +#[allow(clippy::large_enum_variant)] +enum DeferralSource { + Prover(DeferralProver), + PathProver(DeferralPathProver), +} + +#[cfg(feature = "root-prover")] +enum RootSource { + Params(SystemParams), + Pk(RootProvingKey), +} + +#[cfg(feature = "evm-prove")] +enum Halo2Source { + Config { + shape: StaticVerifierShape, + config: Halo2Config, + }, + Pk(Halo2ProvingKey), +} + +/// Construction-only API for [`GenericSdk`]. +/// +/// Each proving layer has one source of truth: either user-supplied config/params or a +/// pre-generated proving key. `build()` normalizes those sources into an immutable [`GenericSdk`]. +pub struct GenericSdkBuilder +where + E: StarkEngine, + VB: VmBuilder, + VB::VmConfig: VmExecutionConfig, +{ + app_source: Option>, + agg_source: Option, + #[cfg(feature = "root-prover")] + root_source: Option, + agg_tree_config: Option, + transpiler: Option>, + deferral_source: Option, + #[cfg(feature = "evm-prove")] + halo2_source: Option, + #[cfg(feature = "evm-prove")] + halo2_params_reader: Option, + _phantom: PhantomData, +} + +impl GenericSdkBuilder +where + E: StarkEngine, + VB: VmBuilder, + VB::VmConfig: VmExecutionConfig, +{ + /// Creates an empty builder with no configured proving layers. + pub fn new() -> Self { + Self::default() + } + + fn set_once(slot: &mut Option, field_name: &str, value: T) { + assert!(slot.is_none(), "{field_name} already set"); + *slot = Some(value); + } + + fn init_once_lock(value: Option, field_name: &str) -> OnceLock { + let lock = OnceLock::new(); + if let Some(value) = value { + assert!( + lock.set(value).is_ok(), + "{field_name} should only be initialized once" + ); + } + lock + } + + fn agg_config_from_pk(agg_pk: &AggProvingKey) -> AggregationConfig { + AggregationConfig { + params: AggregationSystemParams { + leaf: agg_pk.prefix.leaf.params.clone(), + internal: agg_pk.internal_recursive.params.clone(), + }, + } + } + + #[cfg(feature = "evm-prove")] + fn halo2_shape_from_pk(halo2_pk: &Halo2ProvingKey) -> StaticVerifierShape { + halo2_pk.verifier.shape + } + + #[cfg(feature = "evm-prove")] + fn halo2_config_from_pk(halo2_pk: &Halo2ProvingKey) -> Halo2Config { + Halo2Config { + wrapper_k: Some(halo2_pk.wrapper.pinning.metadata.config_params.k), + profiling: halo2_pk.profiling, + } + } + + fn build_deferral_path_prover( + agg_config: &AggregationConfig, + deferral_prover: DeferralProver, + ) -> Arc { + let agg_prover = AggProver::new( + deferral_prover.def_hook_prover.get_vk(), + agg_config.clone(), + AggregationTreeConfig::deferral(), + Some(deferral_prover.def_hook_prover.get_cached_commit()), + ); + Arc::new(DeferralPathProver { + deferral_prover: Arc::new(deferral_prover), + agg_prover: Arc::new(agg_prover), + }) + } + + fn require_dependency( + has_value: bool, + value_name: &str, + has_dependency: bool, + dependency_name: &str, + ) -> Result<(), SdkError> { + if has_value && !has_dependency { + return Err(SdkError::Other(eyre!( + "`{value_name}` requires `{dependency_name}` to also be set" + ))); + } + Ok(()) + } + + fn normalize_app_source( + app_source: AppSource, + ) -> (AppConfig, Option>) { + match app_source { + AppSource::Config(app_config) => (app_config, None), + AppSource::Pk(app_pk) => { + let app_config = app_pk.app_config(); + (app_config, Some(app_pk)) + } + } + } + + fn normalize_agg_source(agg_source: AggSource) -> (AggregationConfig, Option) { + match agg_source { + AggSource::Params(agg_params) => (AggregationConfig { params: agg_params }, None), + AggSource::Pk(agg_pk) => { + let agg_config = Self::agg_config_from_pk(&agg_pk); + (agg_config, Some(agg_pk)) + } + } + } + + #[cfg(feature = "root-prover")] + fn normalize_root_source(root_source: RootSource) -> (SystemParams, Option) { + match root_source { + RootSource::Params(root_params) => (root_params, None), + RootSource::Pk(root_pk) => (root_pk.root_pk.params.clone(), Some(root_pk)), + } + } + + #[cfg(feature = "evm-prove")] + fn normalize_halo2_source( + halo2_source: Halo2Source, + ) -> (StaticVerifierShape, Halo2Config, Option) { + match halo2_source { + Halo2Source::Config { shape, config } => (shape, config, None), + Halo2Source::Pk(halo2_pk) => ( + Self::halo2_shape_from_pk(&halo2_pk), + Self::halo2_config_from_pk(&halo2_pk), + Some(halo2_pk), + ), + } + } + + /// Uses the provided app configuration as the source of truth for app key generation. + pub fn app_config(mut self, app_config: AppConfig) -> Self { + Self::set_once( + &mut self.app_source, + "app_source", + AppSource::Config(app_config), + ); + self + } + + /// Seeds the SDK with a pre-generated app proving key and derives the app config from it. + pub fn app_pk(mut self, app_pk: AppProvingKey) -> Self { + Self::set_once(&mut self.app_source, "app_source", AppSource::Pk(app_pk)); + self + } + + /// Uses the provided aggregation parameters to generate aggregation proving material lazily. + pub fn agg_params(mut self, agg_params: AggregationSystemParams) -> Self { + Self::set_once( + &mut self.agg_source, + "agg_source", + AggSource::Params(agg_params), + ); + self + } + + /// Seeds the SDK with a pre-generated aggregation proving key. + pub fn agg_pk(mut self, agg_pk: AggProvingKey) -> Self { + Self::set_once(&mut self.agg_source, "agg_source", AggSource::Pk(agg_pk)); + self + } + + #[cfg(feature = "root-prover")] + /// Uses the provided root prover parameters to generate the root proving key lazily. + pub fn root_params(mut self, root_params: SystemParams) -> Self { + Self::set_once( + &mut self.root_source, + "root_source", + RootSource::Params(root_params), + ); + self + } + + #[cfg(feature = "root-prover")] + /// Seeds the SDK with a pre-generated root proving key. + pub fn root_pk(mut self, root_pk: RootProvingKey) -> Self { + Self::set_once( + &mut self.root_source, + "root_source", + RootSource::Pk(root_pk), + ); + self + } + + /// Overrides the aggregation tree fanout used when constructing aggregation provers. + pub fn agg_tree_config(mut self, agg_tree_config: AggregationTreeConfig) -> Self { + Self::set_once( + &mut self.agg_tree_config, + "agg_tree_config", + agg_tree_config, + ); + self + } + + /// Sets the transpiler used to convert guest ELFs into + /// [`VmExe`](openvm_circuit::arch::instructions::exe::VmExe)s. + pub fn transpiler(mut self, transpiler: Transpiler) -> Self { + Self::set_once(&mut self.transpiler, "transpiler", transpiler); + self + } + + /// Builds the SDK without inferring a transpiler from the app source. + /// + /// This is useful when callers only operate on pre-transpiled + /// [`VmExe`](openvm_circuit::arch::instructions::exe::VmExe) values and want ELF conversion + /// to remain unavailable unless a transpiler was explicitly supplied via + /// [`Self::transpiler`]. + pub fn build_without_transpiler(self) -> Result, SdkError> + where + VB: Default, + { + let app_source = self + .app_source + .ok_or_else(|| SdkError::Other(eyre!("`app_config` or `app_pk` must be set")))?; + let agg_source = self + .agg_source + .ok_or_else(|| SdkError::Other(eyre!("`agg_params` or `agg_pk` must be set")))?; + #[cfg(feature = "root-prover")] + let root_source = self + .root_source + .unwrap_or_else(|| RootSource::Params(root_params_with_100_bits_security())); + #[cfg(feature = "evm-prove")] + let halo2_source = self.halo2_source.unwrap_or(Halo2Source::Config { + shape: StaticVerifierShape::default(), + config: Halo2Config { + wrapper_k: None, + profiling: false, + }, + }); + + #[cfg(feature = "evm-prove")] + Self::require_dependency( + matches!(halo2_source, Halo2Source::Pk(_)), + "halo2_pk", + matches!(root_source, RootSource::Pk(_)), + "root_pk", + )?; + #[cfg(feature = "root-prover")] + Self::require_dependency( + matches!(root_source, RootSource::Pk(_)), + "root_pk", + matches!(agg_source, AggSource::Pk(_)), + "agg_pk", + )?; + Self::require_dependency( + matches!(agg_source, AggSource::Pk(_)), + "agg_pk", + matches!(app_source, AppSource::Pk(_)), + "app_pk", + )?; + + let Self { + app_source: _, + agg_source: _, + #[cfg(feature = "root-prover")] + root_source: _, + agg_tree_config, + transpiler, + deferral_source, + #[cfg(feature = "evm-prove")] + halo2_source: _, + #[cfg(feature = "evm-prove")] + halo2_params_reader, + _phantom: _, + } = self; + + let (app_config, app_pk_seed) = Self::normalize_app_source(app_source); + let (agg_config, agg_pk_seed) = Self::normalize_agg_source(agg_source); + #[cfg(feature = "root-prover")] + let (root_params, root_pk_seed) = Self::normalize_root_source(root_source); + + let executor = VmExecutor::new(app_config.app_vm_config.clone()) + .map_err(|e| SdkError::Vm(e.into()))?; + let agg_tree_config = agg_tree_config.unwrap_or_default(); + + let def_path_prover = match deferral_source { + Some(DeferralSource::Prover(deferral_prover)) => Some( + Self::build_deferral_path_prover(&agg_config, deferral_prover), + ), + Some(DeferralSource::PathProver(deferral_path_prover)) => { + Some(Arc::new(deferral_path_prover)) + } + None => None, + }; + let def_hook_cached_commit = def_path_prover + .as_ref() + .map(|def_path_prover| def_path_prover.def_hook_cached_commit()); + #[cfg(feature = "root-prover")] + let def_hook_commit = def_path_prover + .as_ref() + .map(|def_path_prover| def_path_prover.def_hook_commit()); + + let app_vm_vk = app_pk_seed + .as_ref() + .map(|app_pk| Arc::new(app_pk.app_vm_pk.vm_pk.get_vk())); + let app_pk = Self::init_once_lock(app_pk_seed, "app_pk"); + + let agg_prover_seed = agg_pk_seed.map(|agg_pk| { + let app_vm_vk = app_vm_vk.expect("validated `agg_pk` dependency on `app_pk`"); + Arc::new(AggProver::from_pk( + app_vm_vk, + agg_pk, + agg_tree_config, + def_hook_cached_commit, + )) + }); + + #[cfg(feature = "root-prover")] + let root_prover_seed = root_pk_seed.map(|root_pk| { + let agg_prover = agg_prover_seed + .as_ref() + .expect("validated `root_pk` dependency on `agg_pk`"); + let system_config = app_config.app_vm_config.as_ref(); + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + let internal_recursive_vk_commit = agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap() + .commitment + .into(); + + Arc::new(RootProver::from_pk( + agg_prover.internal_recursive_prover.get_vk(), + internal_recursive_vk_commit, + root_pk.root_pk, + memory_dimensions, + num_user_pvs, + def_hook_commit, + Some(root_pk.trace_heights), + )) + }); + + #[cfg(feature = "evm-prove")] + let halo2_params_reader = + halo2_params_reader.unwrap_or_else(CacheHalo2ParamsReader::new_with_default_params_dir); + #[cfg(feature = "evm-prove")] + let (halo2_shape, halo2_config, halo2_pk_seed) = Self::normalize_halo2_source(halo2_source); + #[cfg(feature = "evm-prove")] + let halo2_prover_seed = + halo2_pk_seed.map(|halo2_pk| Halo2Prover::new(&halo2_params_reader, halo2_pk)); + + Ok(GenericSdk { + app_config, + agg_config, + agg_tree_config, + #[cfg(feature = "root-prover")] + root_params, + #[cfg(feature = "evm-prove")] + halo2_shape, + #[cfg(feature = "evm-prove")] + halo2_config, + app_vm_builder: Default::default(), + transpiler, + executor, + app_pk, + agg_prover: Self::init_once_lock(agg_prover_seed, "agg_prover"), + #[cfg(feature = "root-prover")] + root_prover: Self::init_once_lock(root_prover_seed, "root_prover"), + def_path_prover, + #[cfg(feature = "evm-prove")] + halo2_params_reader, + #[cfg(feature = "evm-prove")] + halo2_prover: Self::init_once_lock(halo2_prover_seed, "halo2_prover"), + _phantom: PhantomData, + }) + } + + /// Builds the SDK, deriving a default transpiler from the app source when one was not + /// explicitly supplied via [`Self::transpiler`]. + pub fn build(mut self) -> Result, SdkError> + where + VB: Default, + VB::VmConfig: TranspilerConfig, + { + if self.transpiler.is_none() { + self.transpiler = self.app_source.as_ref().map(|app_source| match app_source { + AppSource::Config(app_config) => app_config.app_vm_config.transpiler(), + AppSource::Pk(app_pk) => app_pk.app_vm_pk.vm_config.transpiler(), + }); + } + self.build_without_transpiler() + } + + /// Enables deferrals in this SDK build. The [`DeferralProver`] must be created ahead of time + /// because the [`openvm_deferral_circuit::DeferralExtension`] should be created using + /// [`DeferralProver::make_extension`], which generates the `def_circuit_commits` needed by the + /// VM config. + pub fn deferral_prover(mut self, deferral_prover: DeferralProver) -> Self { + Self::set_once( + &mut self.deferral_source, + "deferral_source", + DeferralSource::Prover(deferral_prover), + ); + self + } + + /// Enables deferrals in this SDK build using a pre-built [`DeferralPathProver`]. + /// + /// This is mutually exclusive with [`Self::deferral_prover`]. Use this when the deferral + /// aggregation path has already been constructed, for example by + /// [`DeferralPathProver::verify_stark`]. + pub fn deferral_path_prover(mut self, deferral_path_prover: DeferralPathProver) -> Self { + Self::set_once( + &mut self.deferral_source, + "deferral_source", + DeferralSource::PathProver(deferral_path_prover), + ); + self + } + + #[cfg(feature = "evm-prove")] + /// Uses the provided Halo2 verifier shape and config to generate Halo2 proving material lazily. + pub fn halo2_config(mut self, shape: StaticVerifierShape, config: Halo2Config) -> Self { + Self::set_once( + &mut self.halo2_source, + "halo2_source", + Halo2Source::Config { shape, config }, + ); + self + } + + #[cfg(feature = "evm-prove")] + /// Seeds the SDK with a pre-generated Halo2 proving key. + pub fn halo2_pk(mut self, halo2_pk: Halo2ProvingKey) -> Self { + Self::set_once( + &mut self.halo2_source, + "halo2_source", + Halo2Source::Pk(halo2_pk), + ); + self + } + + #[cfg(feature = "evm-prove")] + /// Overrides the directory used to read or cache Halo2 parameters. + pub fn halo2_params_dir(mut self, params_dir: impl AsRef) -> Self { + Self::set_once( + &mut self.halo2_params_reader, + "halo2_params_reader", + CacheHalo2ParamsReader::new(params_dir), + ); + self + } +} + +impl Default for GenericSdkBuilder +where + E: StarkEngine, + VB: VmBuilder, + VB::VmConfig: VmExecutionConfig, +{ + fn default() -> Self { + Self { + app_source: None, + agg_source: None, + #[cfg(feature = "root-prover")] + root_source: None, + agg_tree_config: None, + transpiler: None, + deferral_source: None, + #[cfg(feature = "evm-prove")] + halo2_source: None, + #[cfg(feature = "evm-prove")] + halo2_params_reader: None, + _phantom: PhantomData, + } + } +} + +impl GenericSdk +where + E: StarkEngine, + VB: VmBuilder, + VB::VmConfig: VmExecutionConfig, +{ + /// Returns a builder for constructing an immutable [`GenericSdk`]. + pub fn builder() -> GenericSdkBuilder { + GenericSdkBuilder::new() + } +} diff --git a/patches/openvm-sdk/src/compiled.rs b/patches/openvm-sdk/src/compiled.rs new file mode 100644 index 00000000..80f09c2c --- /dev/null +++ b/patches/openvm-sdk/src/compiled.rs @@ -0,0 +1,66 @@ +use openvm_circuit::arch::execution_mode::{MeteredCostCtx, MeteredCtx}; +#[cfg(not(feature = "rvr"))] +use openvm_circuit::arch::{execution_mode::ExecutionCtx, InterpretedInstance}; + +use crate::F; + +cfg_if::cfg_if! { + if #[cfg(feature = "rvr")] { + use openvm_circuit::arch::rvr::{ + RvrMeteredCostInstance, RvrMeteredInstance, RvrPureInstance, + }; + pub type CompiledExePure<'a, F> = RvrPureInstance<'a, F>; + pub type MeteredInstance<'a, F> = RvrMeteredInstance<'a, F>; + pub type MeteredCostInstance<'a, F> = RvrMeteredCostInstance<'a, F>; + } else if #[cfg(feature = "aot")] { + use openvm_circuit::arch::AotInstance; + pub type CompiledExePure<'a, F> = AotInstance<'a, F, ExecutionCtx>; + pub type MeteredInstance<'a, F> = AotInstance<'a, F, MeteredCtx>; + // AOT has no dedicated metered-cost backend; fall back to the interpreter. + pub type MeteredCostInstance<'a, F> = InterpretedInstance<'a, F, MeteredCostCtx>; + } else { + pub type CompiledExePure<'a, F> = InterpretedInstance<'a, F, ExecutionCtx>; + pub type MeteredInstance<'a, F> = InterpretedInstance<'a, F, MeteredCtx>; + pub type MeteredCostInstance<'a, F> = InterpretedInstance<'a, F, MeteredCostCtx>; + } +} + +/// Bundles a [`MeteredInstance`] with a precomputed [`MeteredCtx`] so each execution +/// just clones the ctx instead of rebuilding from the proving key. +pub struct CompiledExeMetered<'a> { + pub instance: MeteredInstance<'a, F>, + pub ctx: MeteredCtx, +} + +pub struct CompiledExeMeteredCost<'a> { + pub instance: MeteredCostInstance<'a, F>, + pub ctx: MeteredCostCtx, +} + +#[cfg(feature = "rvr")] +impl CompiledExeMetered<'_> { + /// Persist the compiled shared library into `dir`. Returns the path of + /// the copied `.so`/`.dylib`. The `MeteredCtx` is not persisted — it is + /// rebuilt from the proving key on load via + /// [`Sdk::load_compiled_metered`](crate::Sdk::load_compiled_metered). + pub fn save( + &self, + dir: &std::path::Path, + ) -> Result { + self.instance.save(dir) + } +} + +#[cfg(feature = "rvr")] +impl CompiledExeMeteredCost<'_> { + /// Persist the compiled shared library into `dir`. Returns the path of + /// the copied `.so`/`.dylib`. The `MeteredCostCtx` is not persisted — it + /// is rebuilt on load via + /// [`Sdk::load_compiled_metered_cost`](crate::Sdk::load_compiled_metered_cost). + pub fn save( + &self, + dir: &std::path::Path, + ) -> Result { + self.instance.save(dir) + } +} diff --git a/patches/openvm-sdk/src/config.rs b/patches/openvm-sdk/src/config.rs new file mode 100644 index 00000000..2d05fe3a --- /dev/null +++ b/patches/openvm-sdk/src/config.rs @@ -0,0 +1,112 @@ +use clap::Args; +use openvm_sdk_config::SdkVmConfig; +use openvm_stark_backend::SystemParams; +use openvm_stark_sdk::config::{ + app_params_with_100_bits_security, internal_params_with_100_bits_security, + leaf_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT, +}; +pub use openvm_stark_sdk::config::{ + DEFAULT_APP_LOG_BLOWUP, DEFAULT_APP_L_SKIP, DEFAULT_INTERNAL_LOG_BLOWUP, + DEFAULT_LEAF_LOG_BLOWUP, DEFAULT_ROOT_LOG_BLOWUP, +}; +use serde::{Deserialize, Serialize}; + +// WARNING: These currently serve as both the DEFAULT and MAXIMUM number of +// children for the leaf and internal aggregation layers, as the max number +// of children is a const generic in the recursion circuit. We may change +// these as needed, but note that a disparity in max and actual number of +// leaf/internal children will cause a performance loss. +pub const MAX_NUM_CHILDREN_LEAF: usize = 4; +pub const MAX_NUM_CHILDREN_INTERNAL: usize = 3; + +fn default_system_params() -> SystemParams { + app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT) +} + +#[derive(Clone, Debug, Serialize, Deserialize, derive_new::new)] +pub struct AppConfig { + pub app_vm_config: VC, + #[serde(default = "default_system_params")] + pub system_params: SystemParams, +} + +impl AppConfig { + pub fn standard(params: SystemParams) -> Self { + Self::new(SdkVmConfig::standard(), params) + } + + pub fn riscv64(params: SystemParams) -> Self { + Self::new(SdkVmConfig::riscv64(), params) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AggregationConfig { + pub params: AggregationSystemParams, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AggregationSystemParams { + pub leaf: SystemParams, + pub internal: SystemParams, +} + +impl Default for AggregationSystemParams { + fn default() -> Self { + Self { + leaf: leaf_params_with_100_bits_security(), + internal: internal_params_with_100_bits_security(), + } + } +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Args)] +pub struct AggregationTreeConfig { + /// Each leaf verifier circuit will aggregate this many App VM proofs. + #[arg( + long, + default_value_t = MAX_NUM_CHILDREN_LEAF, + help = "Number of children per leaf verifier circuit", + help_heading = "Aggregation Tree Options" + )] + pub num_children_leaf: usize, + /// Each internal verifier circuit will aggregate this many proofs, + /// where each proof may be of either leaf or internal verifier (self) circuit. + #[arg( + long, + default_value_t = MAX_NUM_CHILDREN_INTERNAL, + help = "Number of children per internal verifier circuit", + help_heading = "Aggregation Tree Options" + )] + pub num_children_internal: usize, +} + +impl Default for AggregationTreeConfig { + fn default() -> Self { + Self { + num_children_leaf: MAX_NUM_CHILDREN_LEAF, + num_children_internal: MAX_NUM_CHILDREN_INTERNAL, + } + } +} + +impl AggregationTreeConfig { + pub const fn deferral() -> Self { + Self { + num_children_leaf: 2, + num_children_internal: 2, + } + } +} + +/// Configuration for the Halo2 proving and wrapper keygen. +#[cfg(feature = "evm-prove")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Halo2Config { + /// The degree `k` for the wrapper circuit. If `None`, auto-tune to pick the + /// smallest `k` that results in a single advice column. Note: that `k` for + /// the verifier circuit is determined by StaticVerifierShape. + pub wrapper_k: Option, + /// Whether to collect detailed profiling metrics during proving. + pub profiling: bool, +} diff --git a/patches/openvm-sdk/src/error.rs b/patches/openvm-sdk/src/error.rs new file mode 100644 index 00000000..169eea84 --- /dev/null +++ b/patches/openvm-sdk/src/error.rs @@ -0,0 +1,32 @@ +use openvm_circuit::arch::{VirtualMachineError, VmVerificationError}; +use openvm_transpiler::transpiler::TranspilerError; +use openvm_verify_stark_host::error::VerifyStarkError; +use thiserror::Error; + +use crate::SC; + +#[derive(Error, Debug)] +pub enum SdkError { + #[error("I/O error: {0}")] + Io(#[from] std::io::Error), + #[error("Failed to build guest: code = {0}")] + BuildFailedWithCode(i32), + #[error("Failed to build guest (OPENVM_SKIP_BUILD is set)")] + BuildFailed, + #[error("SDK must set a transpiler")] + TranspilerNotAvailable, + #[error("Transpiler error: {0}")] + Transpiler(#[from] TranspilerError), + #[error("VM error: {0}")] + Vm(#[from] VirtualMachineError), + #[error("STARK verification failed with error: {0}")] + VerifyStark(#[from] VerifyStarkError), + #[error("Other error: {0}")] + Other(#[from] eyre::Error), +} + +impl From> for SdkError { + fn from(error: VmVerificationError) -> Self { + SdkError::Other(error.into()) + } +} diff --git a/patches/openvm-sdk/src/fs.rs b/patches/openvm-sdk/src/fs.rs new file mode 100644 index 00000000..535deb38 --- /dev/null +++ b/patches/openvm-sdk/src/fs.rs @@ -0,0 +1,217 @@ +#[cfg(feature = "evm-prove")] +use std::io::{BufReader, BufWriter, Write}; +use std::{ + fs::{create_dir_all, read, write, File}, + path::Path, +}; + +use eyre::{Report, Result}; +use openvm_stark_backend::codec::{Decode, Encode}; +use serde::{de::DeserializeOwned, Serialize}; + +#[cfg(feature = "evm-prove")] +use crate::{ + keygen::Halo2ProvingKey, + types::{EvmHalo2Verifier, EvmVerifierByteCode}, + OPENVM_VERSION, +}; + +pub const EVM_HALO2_VERIFIER_INTERFACE_NAME: &str = "IOpenVmHalo2Verifier.sol"; +pub const EVM_HALO2_VERIFIER_PARENT_NAME: &str = "Halo2Verifier.sol"; +pub const EVM_HALO2_VERIFIER_BASE_NAME: &str = "OpenVmHalo2Verifier.sol"; +pub const EVM_VERIFIER_ARTIFACT_FILENAME: &str = "verifier.bytecode.json"; + +#[cfg(feature = "evm-prove")] +pub fn read_evm_halo2_verifier_from_folder>(folder: P) -> Result { + use std::fs::read_to_string; + + let folder = folder + .as_ref() + .join("src") + .join(format!("v{OPENVM_VERSION}")); + let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME); + let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME); + let interface_path = folder + .join("interfaces") + .join(EVM_HALO2_VERIFIER_INTERFACE_NAME); + let halo2_verifier_code = read_to_string(&halo2_verifier_code_path) + .map_err(|e| read_error(&halo2_verifier_code_path, e.into()))?; + let openvm_verifier_code = read_to_string(&openvm_verifier_code_path) + .map_err(|e| read_error(&openvm_verifier_code_path, e.into()))?; + let interface = + read_to_string(&interface_path).map_err(|e| read_error(&interface_path, e.into()))?; + + let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME); + let artifact: EvmVerifierByteCode = File::open(&artifact_path) + .map_err(|e| read_error(&artifact_path, e.into())) + .and_then(|file| { + serde_json::from_reader(file).map_err(|e| read_error(&artifact_path, e.into())) + })?; + + Ok(EvmHalo2Verifier { + halo2_verifier_code, + openvm_verifier_code, + openvm_verifier_interface: interface, + artifact, + }) +} + +/// Writes three Solidity contracts into the following folder structure: +/// +/// ```text +/// halo2/ +/// └── src/ +/// └── v[OPENVM_VERSION]/ +/// ├── interfaces/ +/// │ └── IOpenVmHalo2Verifier.sol +/// ├── OpenVmHalo2Verifier.sol +/// └── Halo2Verifier.sol +/// ``` +/// +/// If the relevant directories do not exist, they will be created. +#[cfg(feature = "evm-prove")] +pub fn write_evm_halo2_verifier_to_folder>( + verifier: EvmHalo2Verifier, + folder: P, +) -> Result<()> { + let folder = folder + .as_ref() + .join("src") + .join(format!("v{OPENVM_VERSION}")); + if !folder.exists() { + create_dir_all(&folder)?; // Make sure directories exist + } + + let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME); + let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME); + let interface_path = folder + .join("interfaces") + .join(EVM_HALO2_VERIFIER_INTERFACE_NAME); + + if let Some(parent) = interface_path.parent() { + create_dir_all(parent)?; + } + + write(halo2_verifier_code_path, verifier.halo2_verifier_code) + .expect("Failed to write halo2 verifier code"); + write(openvm_verifier_code_path, verifier.openvm_verifier_code) + .expect("Failed to write openvm halo2 verifier code"); + write(interface_path, verifier.openvm_verifier_interface) + .expect("Failed to write openvm halo2 verifier interface"); + + let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME); + serde_json::to_writer(File::create(artifact_path)?, &verifier.artifact)?; + + Ok(()) +} + +pub fn read_object_from_file>(path: P) -> Result { + read_from_file_bitcode(path) +} + +pub fn write_object_to_file>(path: P, data: T) -> Result<()> { + write_to_file_bitcode(path, data) +} + +/// Writes a [`Halo2ProvingKey`] to `path` in the streaming Halo2 pk format. +#[cfg(feature = "evm-prove")] +pub fn write_halo2_pk_to_file>(path: P, halo2_pk: &Halo2ProvingKey) -> Result<()> { + if let Some(parent) = path.as_ref().parent() { + create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?; + } + let file = File::create(&path).map_err(|e| write_error(&path, e.into()))?; + let mut writer = BufWriter::new(file); + halo2_pk + .encode(&mut writer) + .map_err(|e| write_error(&path, e.into()))?; + writer.flush().map_err(|e| write_error(&path, e.into()))?; + Ok(()) +} + +/// Reads a [`Halo2ProvingKey`] written by [`write_halo2_pk_to_file`]. +#[cfg(feature = "evm-prove")] +pub fn read_halo2_pk_from_file>(path: P) -> Result { + let file = File::open(&path).map_err(|e| read_error(&path, e.into()))?; + let mut reader = BufReader::new(file); + Halo2ProvingKey::decode(&mut reader).map_err(|e| read_error(&path, e.into())) +} + +fn read_from_file_bitcode>(path: P) -> Result { + let ret = read(&path) + .map_err(|e| read_error(&path, e.into())) + .and_then(|data| { + bitcode::deserialize(&data).map_err(|e: bitcode::Error| read_error(&path, e.into())) + })?; + Ok(ret) +} + +fn write_to_file_bitcode>(path: P, data: T) -> Result<()> { + if let Some(parent) = path.as_ref().parent() { + create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?; + } + bitcode::serialize(&data) + .map_err(|e| write_error(&path, e.into())) + .and_then(|bytes| write(&path, bytes).map_err(|e| write_error(&path, e.into())))?; + Ok(()) +} + +pub fn read_from_file_json>(path: P) -> Result { + let ret: T = File::open(&path) + .and_then(|file| serde_json::from_reader(file).map_err(|e| e.into())) + .map_err(|e| read_error(&path, e.into()))?; + Ok(ret) +} + +pub fn write_to_file_json>(path: P, data: T) -> Result<()> { + if let Some(parent) = path.as_ref().parent() { + create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?; + } + File::create(&path) + .and_then(|file| serde_json::to_writer_pretty(file, &data).map_err(|e| e.into())) + .map_err(|e| write_error(&path, e.into()))?; + Ok(()) +} + +pub fn read_from_file_bytes>, P: AsRef>(path: P) -> Result { + let bytes = read(&path).map_err(|e| read_error(&path, e.into()))?; + Ok(T::from(bytes)) +} + +pub fn write_to_file_bytes>, P: AsRef>(path: P, data: T) -> Result<()> { + if let Some(parent) = path.as_ref().parent() { + create_dir_all(parent)?; + } + write(path, data.into())?; + Ok(()) +} + +pub fn decode_from_file>(path: P) -> Result { + let reader = &mut File::open(&path).map_err(|e| read_error(&path, e.into()))?; + let ret = T::decode(reader).map_err(|e| read_error(&path, e.into()))?; + Ok(ret) +} + +pub fn encode_to_file>(path: P, data: T) -> Result<()> { + if let Some(parent) = path.as_ref().parent() { + create_dir_all(parent)?; + } + let writer = &mut File::create(path)?; + data.encode(writer)?; + Ok(()) +} + +fn read_error>(path: P, error: Report) -> Report { + eyre::eyre!( + "reading from {} failed with the following error:\n {}", + path.as_ref().display(), + error, + ) +} + +fn write_error>(path: P, error: Report) -> Report { + eyre::eyre!( + "writing to {} failed with the following error:\n {}", + path.as_ref().display(), + error, + ) +} diff --git a/patches/openvm-sdk/src/halo2_params.rs b/patches/openvm-sdk/src/halo2_params.rs new file mode 100644 index 00000000..3959dfe7 --- /dev/null +++ b/patches/openvm-sdk/src/halo2_params.rs @@ -0,0 +1,59 @@ +use std::{ + collections::HashMap, + io::BufReader, + path::{Path, PathBuf}, + sync::{Arc, Mutex}, +}; + +use openvm_static_verifier::{Halo2Params, Halo2ParamsReader}; + +/// Caching reader for Halo2 KZG parameters. +/// +/// Reads SRS files from a directory and caches them in memory for reuse. +pub struct CacheHalo2ParamsReader { + params_dir: PathBuf, + cached: Mutex>>, +} + +impl Halo2ParamsReader for CacheHalo2ParamsReader { + fn read_params(&self, k: usize) -> Arc { + self.read_params(k) + } +} + +impl CacheHalo2ParamsReader { + pub fn new(params_dir: impl AsRef) -> Self { + Self { + params_dir: params_dir.as_ref().to_path_buf(), + cached: Mutex::new(HashMap::new()), + } + } + + /// Create a reader using the default params directory: `~/.openvm/params/`. + pub fn new_with_default_params_dir() -> Self { + let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string()); + let params_dir = PathBuf::from(home).join(".openvm").join("params"); + Self::new(params_dir) + } + + /// Read the KZG params for a given `k` value, caching the result. + pub fn read_params(&self, k: usize) -> Arc { + let mut cache = self.cached.lock().unwrap(); + if let Some(params) = cache.get(&k) { + return params.clone(); + } + let path = self.params_dir.join(format!("kzg_bn254_{k}.srs")); + let file = std::fs::File::open(&path) + .unwrap_or_else(|e| panic!("Failed to open params file {}: {e}", path.display())); + let mut reader = BufReader::new(file); + + // read_custom with RawBytes format + let params = + Halo2Params::read_custom(&mut reader, halo2_base::halo2_proofs::SerdeFormat::RawBytes) + .unwrap_or_else(|e| panic!("Failed to read params from {}: {e}", path.display())); + + let params = Arc::new(params); + cache.insert(k, params.clone()); + params + } +} diff --git a/patches/openvm-sdk/src/keygen/dummy.rs b/patches/openvm-sdk/src/keygen/dummy.rs new file mode 100644 index 00000000..6681a9b9 --- /dev/null +++ b/patches/openvm-sdk/src/keygen/dummy.rs @@ -0,0 +1,149 @@ +use std::sync::Arc; + +use eyre::Result; +use openvm_circuit::arch::{ + instructions::{ + exe::VmExe, instruction::Instruction, program::Program, LocalOpcode, SystemOpcode, + }, + Executor, MeteredExecutor, PreflightExecutor, SystemConfig, VmBuilder, VmExecutionConfig, +}; +use openvm_continuations::{prover::engine_device_ctx, RootSC}; +use openvm_stark_backend::{ + keygen::types::MultiStarkProvingKey, p3_field::PrimeField32, prover::ProvingContext, + StarkEngine, SystemParams, Val, +}; +#[cfg(feature = "evm-prove")] +use { + crate::prover::{EvmProver, RootProver}, + openvm_stark_backend::proof::Proof, +}; + +use crate::{ + prover::{vm::types::VmProvingKey, AggProver, DeferralPathProver, StarkProver}, + StdIn, F, SC, +}; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_continuations::prover::RootGpuProver as RootInnerProver; + type RootE = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine; + } else { + use openvm_continuations::prover::RootCpuProver as RootInnerProver; + type RootE = openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; + } +} + +fn dummy_terminate_exe() -> Arc> { + let dummy_program = Program::::from_instructions(&[Instruction::from_isize( + SystemOpcode::TERMINATE.global_opcode(), + 0, + 0, + 0, + 0, + 0, + )]); + Arc::new(VmExe::new(dummy_program)) +} + +pub fn compute_root_proof_heights( + vm_builder: VB, + app_vm_pk: &VmProvingKey, + agg_prover: Arc, + root_params: SystemParams, + def_prover: Option>, +) -> Result<(Vec, Arc>)> +where + E: StarkEngine, + VB: VmBuilder, + VB::VmConfig: VmExecutionConfig + AsRef, + Val: PrimeField32, + >::Executor: + Executor + MeteredExecutor + PreflightExecutor, +{ + let dummy_exe = dummy_terminate_exe(); + + let system_config = app_vm_pk.vm_config.as_ref(); + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + + let def_hook_commit = def_prover.as_ref().map(|p| p.def_hook_commit().into()); + + let mut stark_prover = StarkProver::::new( + vm_builder, + app_vm_pk, + dummy_exe, + agg_prover.clone(), + def_prover, + )?; + stark_prover.set_program_name("root_keygen"); + let (agg_proof, _) = stark_prover.prove(StdIn::default(), &[])?; + + let root_prover = RootInnerProver::new::( + agg_prover.internal_recursive_prover.get_vk(), + agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap() + .commitment + .into(), + root_params, + memory_dimensions, + num_user_pvs, + def_hook_commit, + None, + ); + + let engine = RootE::new(root_prover.get_pk().params.clone()); + let root_proving_ctx: ProvingContext<::PB> = root_prover + .generate_proving_ctx( + agg_proof.inner, + &agg_proof.user_pvs_proof, + agg_proof.deferral_merkle_proofs.as_ref(), + engine_device_ctx(&engine), + ) + .unwrap(); + + let trace_heights = root_proving_ctx + .into_iter() + .map(|(_, air_ctx)| air_ctx.height()) + .collect(); + Ok((trace_heights, root_prover.get_pk())) +} + +/// Generate a dummy root proof for keygen purposes. +/// +/// Runs a trivial TERMINATE-only program through the full EVM prover pipeline +/// (app → aggregation → root) and returns the resulting root proof. +#[cfg(feature = "evm-prove")] +pub fn generate_dummy_root_proof( + vm_builder: VB, + app_vm_pk: &VmProvingKey, + agg_prover: Arc, + def_path_prover: Option>, + root_prover: Arc, +) -> Proof +where + E: StarkEngine, + VB: VmBuilder + Clone, + Val: PrimeField32, + >::Executor: + Executor + MeteredExecutor + PreflightExecutor, +{ + let dummy_exe = dummy_terminate_exe(); + + let mut evm_prover = EvmProver::::new( + vm_builder, + app_vm_pk, + dummy_exe, + agg_prover, + def_path_prover, + root_prover, + None, + ) + .expect("Failed to create dummy EVM prover"); + evm_prover.stark_prover.set_program_name("halo2_keygen"); + + evm_prover + .prove_root(StdIn::default(), &[]) + .expect("Failed to generate dummy root proof") +} diff --git a/patches/openvm-sdk/src/keygen/mod.rs b/patches/openvm-sdk/src/keygen/mod.rs new file mode 100644 index 00000000..4ecd9114 --- /dev/null +++ b/patches/openvm-sdk/src/keygen/mod.rs @@ -0,0 +1,139 @@ +#[cfg(feature = "evm-prove")] +use std::io::{self, Read, Write}; +use std::sync::Arc; + +use openvm_circuit::{ + arch::{AirInventoryError, SystemConfig, VmCircuitConfig, U16_CELL_SIZE}, + system::memory::dimensions::MemoryDimensions, +}; +#[cfg(feature = "root-prover")] +use openvm_continuations::RootSC; +#[cfg(feature = "evm-prove")] +use openvm_stark_backend::codec::{Decode, Encode}; +use openvm_stark_backend::{ + keygen::types::{MultiStarkProvingKey, MultiStarkVerifyingKey}, + StarkEngine, +}; +use openvm_stark_sdk::config::baby_bear_poseidon2::{BabyBearPoseidon2CpuEngine, DuplexSponge}; +use serde::{Deserialize, Serialize}; + +use crate::{config::AppConfig, prover::vm::types::VmProvingKey, SC}; + +#[cfg(feature = "root-prover")] +pub mod dummy; +#[cfg(feature = "evm-prove")] +pub mod static_verifier; + +/// This is lightweight to clone as it contains smart pointers to the proving keys. +#[derive(Clone, Serialize, Deserialize)] +pub struct AppProvingKey { + pub app_vm_pk: Arc>, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct AppVerifyingKey { + pub vk: MultiStarkVerifyingKey, + pub memory_dimensions: MemoryDimensions, + pub num_user_pvs: usize, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct AggPrefixProvingKey { + pub leaf: Arc>, + pub internal_for_leaf: Arc>, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct AggProvingKey { + pub prefix: AggPrefixProvingKey, + pub internal_recursive: Arc>, +} + +#[cfg(feature = "root-prover")] +#[derive(Clone, Serialize, Deserialize)] +pub struct RootProvingKey { + pub root_pk: Arc>, + pub trace_heights: Vec, +} + +impl AppProvingKey +where + VC: Clone + VmCircuitConfig + AsRef, +{ + pub fn keygen(config: AppConfig) -> Result { + let app_engine = BabyBearPoseidon2CpuEngine::::new(config.system_params); + let app_vm_pk = { + let vm_pk = config + .app_vm_config + .create_airs()? + .keygen(app_engine.config()); + VmProvingKey { + vm_config: config.app_vm_config.clone(), + vm_pk: Arc::new(vm_pk), + } + }; + Ok(Self { + app_vm_pk: Arc::new(app_vm_pk), + }) + } + + pub fn num_public_values_bytes(&self) -> usize { + self.app_vm_pk.vm_config.as_ref().num_public_values * U16_CELL_SIZE + } + + pub fn get_app_vk(&self) -> AppVerifyingKey { + let system_config = self.app_vm_pk.vm_config.as_ref(); + AppVerifyingKey { + vk: self.app_vm_pk.vm_pk.get_vk(), + memory_dimensions: system_config.memory_config.memory_dimensions(), + num_user_pvs: system_config.num_public_values, + } + } + + pub fn vm_config(&self) -> &VC { + &self.app_vm_pk.vm_config + } + + pub fn app_config(&self) -> AppConfig { + AppConfig { + app_vm_config: self.vm_config().clone(), + system_params: self.app_vm_pk.vm_pk.params.clone(), + } + } +} + +#[cfg(feature = "evm-prove")] +#[derive(Clone)] +pub struct Halo2ProvingKey { + /// Static verifier to verify a stark proof of the root verifier. + pub verifier: Arc, + /// Wrapper circuit to verify static verifier and reduce the verification costs in the final + /// proof. + pub wrapper: Arc, + /// Whether to collect detailed profiling metrics. + pub profiling: bool, +} + +#[cfg(feature = "evm-prove")] +impl Encode for Halo2ProvingKey { + fn encode(&self, writer: &mut W) -> io::Result<()> { + self.profiling.encode(writer)?; + self.verifier.encode(writer)?; + self.wrapper.encode(writer) + } +} + +#[cfg(feature = "evm-prove")] +impl Decode for Halo2ProvingKey { + fn decode(reader: &mut R) -> io::Result { + Ok(Self { + profiling: bool::decode(reader)?, + verifier: Arc::new(openvm_static_verifier::StaticVerifierProvingKey::decode( + reader, + )?), + wrapper: Arc::new(openvm_static_verifier::Halo2WrapperProvingKey::decode( + reader, + )?), + }) + } +} diff --git a/patches/openvm-sdk/src/keygen/perm.rs b/patches/openvm-sdk/src/keygen/perm.rs new file mode 100644 index 00000000..70e8482b --- /dev/null +++ b/patches/openvm-sdk/src/keygen/perm.rs @@ -0,0 +1,93 @@ +use std::cmp::Reverse; + +#[cfg(feature = "evm-prove")] +use openvm_continuations::verifier::common::types::SpecialAirIds; + +/// Permutation of the AIR IDs to order them by forced trace heights. +pub(crate) struct AirIdPermutation { + pub perm: Vec, +} + +impl AirIdPermutation { + pub fn compute(heights: &[u32]) -> AirIdPermutation { + let mut height_with_air_id: Vec<_> = heights.iter().copied().enumerate().collect(); + height_with_air_id.sort_by_key(|(_, h)| Reverse(*h)); + AirIdPermutation { + perm: height_with_air_id + .into_iter() + .map(|(a_id, _)| a_id) + .collect(), + } + } + #[cfg(feature = "evm-prove")] + pub fn get_special_air_ids(&self) -> SpecialAirIds { + use openvm_circuit::arch::{BOUNDARY_AIR_ID, CONNECTOR_AIR_ID, PROGRAM_AIR_ID}; + + let perm_len = self.perm.len(); + let mut ret = SpecialAirIds { + program_air_id: perm_len, + connector_air_id: perm_len, + public_values_air_id: perm_len, + }; + for (i, &air_id) in self.perm.iter().enumerate() { + if air_id == PROGRAM_AIR_ID { + ret.program_air_id = i; + } else if air_id == CONNECTOR_AIR_ID { + ret.connector_air_id = i; + } else if air_id == BOUNDARY_AIR_ID { + ret.public_values_air_id = i; + } + } + debug_assert_ne!(ret.program_air_id, perm_len, "Program AIR not found"); + debug_assert_ne!(ret.connector_air_id, perm_len, "Connector AIR not found"); + debug_assert_ne!( + ret.public_values_air_id, perm_len, + "Public Values AIR not found" + ); + ret + } + /// arr[i] <- arr[perm[i]] + pub(crate) fn permute(&self, arr: &mut [T]) { + debug_assert_eq!(arr.len(), self.perm.len()); + let mut perm = self.perm.clone(); + for i in 0..perm.len() { + if perm[i] != i { + let mut curr = i; + loop { + let target = perm[curr]; + perm[curr] = curr; + if perm[target] == target { + break; + } + arr.swap(curr, target); + curr = target; + } + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::keygen::perm::AirIdPermutation; + + #[test] + fn test_air_id_permutation() { + { + let perm = AirIdPermutation { + perm: vec![2, 0, 1, 3], + }; + let mut arr = vec![0, 100, 200, 300]; + perm.permute(&mut arr); + assert_eq!(arr, vec![200, 0, 100, 300]); + } + { + let perm = AirIdPermutation { + perm: vec![0, 1, 2, 3], + }; + let mut arr = vec![0, 100, 200, 300]; + perm.permute(&mut arr); + assert_eq!(arr, vec![0, 100, 200, 300]); + } + } +} diff --git a/patches/openvm-sdk/src/keygen/static_verifier.rs b/patches/openvm-sdk/src/keygen/static_verifier.rs new file mode 100644 index 00000000..3dfa6ffa --- /dev/null +++ b/patches/openvm-sdk/src/keygen/static_verifier.rs @@ -0,0 +1,70 @@ +use std::sync::Arc; + +use openvm_continuations::{RootSC, SC}; +use openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey, proof::Proof}; +use openvm_static_verifier::{ + compute_dag_onion_commit, log_heights_per_air_from_proof, Halo2Params, Halo2ParamsReader, + Halo2WrapperProvingKey, StaticVerifierCircuit, StaticVerifierProvingKey, StaticVerifierShape, +}; + +use crate::{config::Halo2Config, keygen::Halo2ProvingKey}; + +/// Generate a [`Halo2ProvingKey`] (static verifier + wrapper) by running a +/// dummy root proof through the pipeline. +/// +/// This is the self-contained keygen flow: +/// 1. Build a [`StaticVerifierProvingKey`] from the root VK and proof shape +/// 2. Generate a dummy snark from the static verifier +/// 3. Build a [`Halo2WrapperProvingKey`] (auto-tuned or fixed `k`) +/// 4. Return the composite [`Halo2ProvingKey`] +#[tracing::instrument(level = "info", fields(group = "halo2_keygen"), skip_all)] +pub fn keygen_halo2( + halo2_config: &Halo2Config, + reader: &impl Halo2ParamsReader, + shape: StaticVerifierShape, + internal_recursive_vk: &MultiStarkVerifyingKey, + root_vk: &MultiStarkVerifyingKey, + dummy_root_proof: &Proof, +) -> Halo2ProvingKey { + let params = reader.read_params(shape.k); + + let verifier = keygen_static_verifier( + ¶ms, + shape, + internal_recursive_vk, + root_vk, + dummy_root_proof, + ); + + let dummy_snark = verifier.generate_dummy_snark(reader); + + let wrapper = if let Some(wrapper_k) = halo2_config.wrapper_k { + Halo2WrapperProvingKey::keygen(&reader.read_params(wrapper_k), dummy_snark) + } else { + Halo2WrapperProvingKey::keygen_auto_tune(reader, dummy_snark) + }; + + Halo2ProvingKey { + verifier: Arc::new(verifier), + wrapper: Arc::new(wrapper), + profiling: halo2_config.profiling, + } +} + +/// Generate a [`StaticVerifierProvingKey`] from a root VK, heights, and a +/// dummy root proof. This is the lower-level keygen without the wrapper. +pub fn keygen_static_verifier( + params: &Halo2Params, + shape: StaticVerifierShape, + internal_recursive_vk: &MultiStarkVerifyingKey, + root_vk: &MultiStarkVerifyingKey, + dummy_root_proof: &Proof, +) -> StaticVerifierProvingKey { + let log_heights = log_heights_per_air_from_proof(dummy_root_proof); + let onion_commit = compute_dag_onion_commit(internal_recursive_vk); + + let circuit = StaticVerifierCircuit::try_new(root_vk.clone(), onion_commit, &log_heights) + .expect("Failed to construct StaticVerifierCircuit"); + + StaticVerifierProvingKey::keygen(params, shape, circuit, dummy_root_proof) +} diff --git a/patches/openvm-sdk/src/lib.rs b/patches/openvm-sdk/src/lib.rs new file mode 100644 index 00000000..c9c74ef6 --- /dev/null +++ b/patches/openvm-sdk/src/lib.rs @@ -0,0 +1,882 @@ +#![cfg_attr(feature = "tco", allow(incomplete_features))] +#![cfg_attr(feature = "tco", feature(explicit_tail_calls))] + +use std::{ + fs::read, + marker::PhantomData, + path::Path, + sync::{Arc, OnceLock}, +}; + +use config::AppConfig; +use getset::Getters; +use keygen::{AppProvingKey, AppVerifyingKey}; +use openvm_build::{ + build_guest_package, find_unique_executable, get_package, GuestOptions, TargetFilter, +}; +// Re-exports +pub use openvm_build::{cargo_command, get_rustup_toolchain_name}; +pub use openvm_circuit; +use openvm_circuit::{ + arch::{ + execution_mode::Segment, instructions::exe::VmExe, Executor, InitFileGenerator, + MeteredExecutor, PreflightExecutor, VirtualMachineError, VmBuilder, VmExecutionConfig, + VmExecutor, U16_CELL_SIZE, + }, + system::memory::merkle::public_values::extract_public_values, +}; +use openvm_continuations::CommitBytes; +use openvm_sdk_config::{SdkVmConfig, SdkVmCpuBuilder, TranspilerConfig}; +use openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey, StarkEngine, SystemParams}; +use openvm_stark_sdk::config::baby_bear_poseidon2::{ + BabyBearPoseidon2CpuEngine as BabyBearPoseidon2Engine, Digest, +}; +#[cfg(feature = "evm-prove")] +use openvm_static_verifier::StaticVerifierShape; +use openvm_transpiler::{ + elf::Elf, openvm_platform::memory::MEM_SIZE, transpiler::Transpiler, FromElf, +}; +use openvm_verify_stark_host::{ + verify_vm_stark_proof_decoded, + vk::{VerificationBaseline, VmStarkVerifyingKey}, + VmStarkProof, +}; + +use crate::{ + config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig}, + keygen::{AggPrefixProvingKey, AggProvingKey}, + prover::{AggProver, AppProver, DeferralPathProver, StarkProver}, + types::{AppExecutionCommit, ExecutableFormat}, +}; +#[cfg(feature = "evm-prove")] +use crate::{halo2_params::CacheHalo2ParamsReader, keygen::Halo2ProvingKey, prover::Halo2Prover}; +#[cfg(feature = "root-prover")] +use crate::{ + keygen::{dummy::compute_root_proof_heights, RootProvingKey}, + prover::{EvmProver, RootProver}, +}; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_sdk_config::SdkVmGpuBuilder; + use openvm_cuda_backend::BabyBearPoseidon2GpuEngine as GpuBabyBearPoseidon2Engine; + pub use GpuSdk as Sdk; + pub type DefaultStarkEngine = GpuBabyBearPoseidon2Engine; + } else { + pub use CpuSdk as Sdk; + pub type DefaultStarkEngine = BabyBearPoseidon2Engine; + } +} + +pub use openvm_stark_sdk::config::baby_bear_poseidon2::{BabyBearPoseidon2Config as SC, F}; + +pub mod builder; +pub mod compiled; +pub mod config; +pub mod fs; +#[cfg(feature = "evm-prove")] +pub mod halo2_params; +pub mod keygen; +pub mod prover; +#[cfg(feature = "evm-verify")] +mod solidity; +pub mod types; +pub mod util; + +#[cfg(all(test, feature = "root-prover"))] +mod tests; + +mod error; +mod stdin; +pub use compiled::{CompiledExeMetered, CompiledExeMeteredCost, CompiledExePure}; +pub use error::SdkError; +pub use stdin::*; + +pub const OPENVM_VERSION: &str = concat!( + env!("CARGO_PKG_VERSION_MAJOR"), + ".", + env!("CARGO_PKG_VERSION_MINOR") +); + +// The SDK is only generic in the engine for the non-root SC. The root SC is fixed to +// BabyBearPoseidon2RootEngine right now. +/// The SDK provides convenience methods and constructors for provers. +/// +/// A built SDK is an immutable proving environment: user-supplied config, params, and pre-generated +/// keys are fixed after construction. Use [`builder`](Self::builder) for advanced initialization, +/// or [`new`](Self::new) / [`new_without_transpiler`](Self::new_without_transpiler) for the +/// common config-driven paths. +/// +/// Internally, the SDK lazily caches proving state that depends only on the app VM config, +/// aggregation config, root params, and optional pre-generated keys. It does not cache any state +/// that depends on the program executable. +/// +/// Some commonly used methods are: +/// - [`compile_and_execute`](Self::compile_and_execute) +/// - [`prove`](Self::prove) +/// - [`verify_proof`](Self::verify_proof) +#[derive(Getters)] +pub struct GenericSdk +where + E: StarkEngine, + VB: VmBuilder, + VB::VmConfig: VmExecutionConfig, +{ + #[getset(get = "pub")] + app_config: AppConfig, + #[getset(get = "pub")] + agg_config: AggregationConfig, + #[getset(get = "pub")] + agg_tree_config: AggregationTreeConfig, + #[cfg(feature = "root-prover")] + #[getset(get = "pub")] + root_params: SystemParams, + #[cfg(feature = "evm-prove")] + #[getset(get = "pub")] + halo2_shape: StaticVerifierShape, + #[cfg(feature = "evm-prove")] + #[getset(get = "pub")] + halo2_config: config::Halo2Config, + + #[getset(get = "pub")] + app_vm_builder: VB, + + transpiler: Option>, + + /// The `executor` may be used to construct different types of interpreters, given the program, + /// for more specific execution purposes. By default, it is recommended to use the + /// [`execute`](GenericSdk::execute) method. + #[getset(get = "pub")] + executor: VmExecutor, + + app_pk: OnceLock>, + agg_prover: OnceLock>, + #[cfg(feature = "root-prover")] + root_prover: OnceLock>, + + def_path_prover: Option>, + + #[cfg(feature = "evm-prove")] + #[getset(get = "pub")] + halo2_params_reader: CacheHalo2ParamsReader, + #[cfg(feature = "evm-prove")] + halo2_prover: OnceLock, + + _phantom: PhantomData, +} + +pub type CpuSdk = GenericSdk; + +#[cfg(feature = "cuda")] +pub type GpuSdk = GenericSdk; + +impl GenericSdk +where + E: StarkEngine, + VB: VmBuilder + Clone + Default, +{ + /// Creates SDK with a standard configuration that includes a set of default VM extensions + /// loaded. + /// + /// **Note**: To use this configuration, your `openvm.toml` must match, including the order of + /// the moduli and elliptic curve parameters of the respective extensions: + /// The `app_vm_config` field of your `openvm.toml` must exactly match the following: + /// + /// ```toml + #[doc = include_str!("../openvm_standard.toml")] + /// ``` + pub fn standard(app_params: SystemParams, agg_params: AggregationSystemParams) -> Self { + GenericSdk::new(AppConfig::standard(app_params), agg_params).unwrap() + } + + /// Creates SDK with a configuration with RISC-V RV64IM and IO VM extensions loaded. + /// + /// **Note**: To use this configuration, your `openvm.toml` must exactly match the following: + /// + /// ```toml + #[doc = include_str!("../openvm_riscv64.toml")] + /// ``` + pub fn riscv64(app_params: SystemParams, agg_params: AggregationSystemParams) -> Self { + GenericSdk::new(AppConfig::riscv64(app_params), agg_params).unwrap() + } +} + +impl GenericSdk +where + E: StarkEngine, + VB: VmBuilder, +{ + /// Creates SDK custom to the given [AppConfig], with a RISC-V transpiler. + pub fn new( + app_config: AppConfig, + agg_params: AggregationSystemParams, + ) -> Result + where + VB: Default, + VB::VmConfig: TranspilerConfig, + { + Self::builder() + .app_config(app_config) + .agg_params(agg_params) + .build() + } + + /// Creates an SDK custom to the given [AppConfig] without configuring a transpiler. + /// + /// **Note**: This function does not set the transpiler, which must be done separately to + /// support RISC-V ELFs. + pub fn new_without_transpiler( + app_config: AppConfig, + agg_params: AggregationSystemParams, + ) -> Result + where + VB: Default, + { + Self::builder() + .app_config(app_config) + .agg_params(agg_params) + .build_without_transpiler() + } + + /// Returns the def_hook_prover cached commit. + pub fn def_hook_cached_commit(&self) -> Option { + self.def_path_prover + .as_ref() + .map(|p| p.def_hook_cached_commit()) + } + + /// Returns the deferral hook commit derived from the deferral aggregation path. + pub fn def_hook_commit(&self) -> Option { + self.def_path_prover.as_ref().map(|p| p.def_hook_commit()) + } + + /// Builds the guest package located at `pkg_dir`. This function requires that the build target + /// is unique and errors otherwise. Returns the built ELF file decoded in the [Elf] type. + pub fn build>( + &self, + guest_opts: GuestOptions, + pkg_dir: P, + target_filter: &Option, + init_file_name: Option<&str>, // If None, we use "openvm-init.rs" + ) -> Result { + self.app_config + .app_vm_config + .write_to_init_file(pkg_dir.as_ref(), init_file_name)?; + let pkg = get_package(pkg_dir.as_ref()); + let target_dir = match build_guest_package(&pkg, &guest_opts, None, target_filter) { + Ok(target_dir) => target_dir, + Err(Some(code)) => { + return Err(SdkError::BuildFailedWithCode(code)); + } + Err(None) => { + return Err(SdkError::BuildFailed); + } + }; + + let elf_path = + find_unique_executable(pkg_dir, target_dir, target_filter).map_err(SdkError::Other)?; + let data = read(&elf_path)?; + Elf::decode(&data, MEM_SIZE as u32).map_err(SdkError::Other) + } + + /// Transpiler for transpiling RISC-V ELF to OpenVM executable. + pub fn transpiler(&self) -> Result<&Transpiler, SdkError> { + self.transpiler + .as_ref() + .ok_or(SdkError::TranspilerNotAvailable) + } + + /// Normalizes an ELF or executable handle into a shared [`VmExe`]. + pub fn convert_to_exe( + &self, + executable: impl Into, + ) -> Result>, SdkError> { + let executable = executable.into(); + let exe = match executable { + ExecutableFormat::Elf(elf) => { + let transpiler = self.transpiler()?.clone(); + Arc::new(VmExe::from_elf(elf, transpiler)?) + } + ExecutableFormat::VmExe(exe) => Arc::new(exe), + ExecutableFormat::SharedVmExe(exe) => exe, + }; + Ok(exe) + } +} + +// The SDK is only functional for SC = BabyBearPoseidon2Config because that is what recursive +// aggregation supports. +impl GenericSdk +where + E: StarkEngine, + VB: VmBuilder + Clone, + >::Executor: + Executor + MeteredExecutor + PreflightExecutor, +{ + /// Compile `app_exe` and execute it, returning the user public values as bytes. + pub fn compile_and_execute( + &self, + app_exe: impl Into, + inputs: StdIn, + ) -> Result, SdkError> { + let compiled = self.compile(app_exe)?; + self.execute(&compiled, inputs) + } + + /// Compile `app_exe` for pure execution. + #[tracing::instrument(name = "sdk.compile", level = "info", skip_all)] + pub fn compile( + &self, + app_exe: impl Into, + ) -> Result, SdkError> { + let exe = self.convert_to_exe(app_exe)?; + self.executor + .instance(&exe) + .map_err(VirtualMachineError::from) + .map_err(SdkError::from) + } + + /// Load a previously saved pure-mode rvr artifact. No compatibility validation is performed. + #[cfg(feature = "rvr")] + pub fn load_compiled( + &self, + lib_path: &std::path::Path, + app_exe: impl Into, + ) -> Result, SdkError> { + let exe = self.convert_to_exe(app_exe)?; + self.executor + .load_instance(lib_path, &exe) + .map_err(VirtualMachineError::from) + .map_err(SdkError::from) + } + + /// Run a [`CompiledExePure`] against `inputs` and extract the user public values. + #[tracing::instrument(name = "sdk.execute", level = "info", skip_all)] + pub fn execute( + &self, + compiled: &CompiledExePure<'_, F>, + inputs: StdIn, + ) -> Result, SdkError> { + let final_memory = compiled + .execute(inputs, None) + .map_err(VirtualMachineError::from)? + .memory; + let public_values = extract_public_values( + self.executor.config.as_ref().num_public_values * U16_CELL_SIZE, + &final_memory.memory, + ); + Ok(public_values) + } + + /// Executes with segmentation for proof generation. + /// Returns both user public values and segments with instruction counts and trace heights. + pub fn compile_and_execute_metered( + &self, + app_exe: impl Into, + inputs: StdIn, + ) -> Result<(Vec, Vec), SdkError> { + let compiled = self.compile_metered(app_exe)?; + self.execute_metered(&compiled, inputs) + } + + /// Compile `app_exe` for metered execution. The returned [`CompiledExeMetered`] bundles + /// a precomputed [`MeteredCtx`](openvm_circuit::arch::execution_mode::MeteredCtx) so + /// subsequent runs just clone it. + #[tracing::instrument(name = "sdk.compile_metered", level = "info", skip_all)] + pub fn compile_metered( + &self, + app_exe: impl Into, + ) -> Result, SdkError> { + let app_prover = self.app_prover(app_exe)?; + + let vm = app_prover.vm(); + let exe = app_prover.exe(); + + let ctx = vm.build_metered_ctx(&exe); + let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); + let instance = self + .executor + .metered_instance(&exe, &executor_idx_to_air_idx) + .map_err(VirtualMachineError::from)?; + Ok(CompiledExeMetered { instance, ctx }) + } + + /// Load a previously saved metered-mode artifact. The `MeteredCtx` + /// is rebuilt. Caller supplies `app_exe`; no compatibility validation is performed. + #[cfg(feature = "rvr")] + pub fn load_compiled_metered( + &self, + lib_path: &std::path::Path, + app_exe: impl Into, + ) -> Result, SdkError> { + let app_prover = self.app_prover(app_exe)?; + let vm = app_prover.vm(); + let exe = app_prover.exe(); + + let ctx = vm.build_metered_ctx(&exe); + let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); + let instance = self + .executor + .load_metered_instance(lib_path, &exe, &executor_idx_to_air_idx) + .map_err(VirtualMachineError::from)?; + Ok(CompiledExeMetered { instance, ctx }) + } + + /// Run a [`CompiledExeMetered`] against `inputs`. + #[tracing::instrument(name = "sdk.execute_metered", level = "info", skip_all)] + pub fn execute_metered( + &self, + compiled: &CompiledExeMetered<'_>, + inputs: StdIn, + ) -> Result<(Vec, Vec), SdkError> { + let (segments, final_state) = compiled + .instance + .execute_metered(inputs, compiled.ctx.clone()) + .map_err(VirtualMachineError::from)?; + let public_values = extract_public_values( + self.executor.config.as_ref().num_public_values * U16_CELL_SIZE, + &final_state.memory.memory, + ); + + Ok((public_values, segments)) + } + + /// Executes with cost metering to measure computational cost in trace cells. + /// Returns both user public values, and cost along with instruction count. + pub fn compile_and_execute_metered_cost( + &self, + app_exe: impl Into, + inputs: StdIn, + ) -> Result<(Vec, (u64, u64)), SdkError> { + let compiled = self.compile_metered_cost(app_exe)?; + self.execute_metered_cost(&compiled, inputs) + } + + /// Compile `app_exe` for metered-cost execution. See [`Self::compile_metered`]. + #[tracing::instrument(name = "sdk.compile_metered_cost", level = "info", skip_all)] + pub fn compile_metered_cost( + &self, + app_exe: impl Into, + ) -> Result, SdkError> { + let app_prover = self.app_prover(app_exe)?; + + let vm = app_prover.vm(); + let exe = app_prover.exe(); + + let ctx = vm.build_metered_cost_ctx(); + let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); + #[cfg(feature = "rvr")] + let instance = self + .executor + .metered_cost_instance(&exe, &executor_idx_to_air_idx, &ctx.widths) + .map_err(VirtualMachineError::from)?; + #[cfg(not(feature = "rvr"))] + let instance = self + .executor + .metered_cost_instance(&exe, &executor_idx_to_air_idx) + .map_err(VirtualMachineError::from)?; + Ok(CompiledExeMeteredCost { instance, ctx }) + } + + /// Load a previously saved metered-cost-mode artifact. The `MeteredCostCtx` is + /// rebuilt. Caller supplies `app_exe`; no compatibility validation is performed. + #[cfg(feature = "rvr")] + pub fn load_compiled_metered_cost( + &self, + lib_path: &std::path::Path, + app_exe: impl Into, + ) -> Result, SdkError> { + let app_prover = self.app_prover(app_exe)?; + let vm = app_prover.vm(); + let exe = app_prover.exe(); + + let ctx = vm.build_metered_cost_ctx(); + let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); + let instance = self + .executor + .load_metered_cost_instance(lib_path, &exe, &executor_idx_to_air_idx, &ctx.widths) + .map_err(VirtualMachineError::from)?; + Ok(CompiledExeMeteredCost { instance, ctx }) + } + + /// Run a [`CompiledExeMeteredCost`] against `inputs`. + #[tracing::instrument(name = "sdk.execute_metered_cost", level = "info", skip_all)] + pub fn execute_metered_cost( + &self, + compiled: &CompiledExeMeteredCost<'_>, + inputs: StdIn, + ) -> Result<(Vec, (u64, u64)), SdkError> { + let (ctx, final_state) = compiled + .instance + .execute_metered_cost(inputs, compiled.ctx.clone()) + .map_err(VirtualMachineError::from)?; + let instret = ctx.instret; + let cost = ctx.cost; + + let public_values = extract_public_values( + self.executor.config.as_ref().num_public_values * U16_CELL_SIZE, + &final_state.memory.memory, + ); + + Ok((public_values, (cost, instret))) + } + + // ======================== Proving Methods ============================ + + /// Generates a single aggregate STARK proof of the full program execution of the given + /// `app_exe` with program inputs `inputs`.\ + /// + /// For convenience, this function also returns the [VerificationBaseline], which is a full + /// commitment to the App [VmExe] and aggregation verifiers. It does **not** depend on the + /// `inputs`. It can be generated separately from the proof by creating a + /// [`prover`](Self::prover) and calling + /// [`app_vm_commit`](StarkProver::app_vm_commit). + /// + /// If STARK aggregation is not needed and a proof whose size may grow linearly with the length + /// of the program runtime is desired, create an [`app_prover`](Self::app_prover) and call + /// [`app_prover.prove(inputs)`](AppProver::prove). + pub fn prove( + &self, + app_exe: impl Into, + inputs: StdIn, + def_inputs: &[DeferralInput], + ) -> Result<(VmStarkProof, VerificationBaseline), SdkError> { + let mut prover = self.prover(app_exe)?; + let proof = prover.prove(inputs, def_inputs)?.0; + let baseline = prover.generate_baseline(); + Ok((proof, baseline)) + } + + #[cfg(feature = "evm-prove")] + /// Generates an EVM-verifiable proof for the given executable and inputs. + pub fn prove_evm( + &self, + app_exe: impl Into, + inputs: StdIn, + def_inputs: &[DeferralInput], + ) -> Result { + let app_exe = self.convert_to_exe(app_exe)?; + let mut evm_prover = self.evm_prover(app_exe)?; + let evm_proof = evm_prover.prove_evm(inputs, def_inputs)?; + Ok(evm_proof) + } + + // ========================= Prover Constructors ========================= + + /// This constructor is for generating app proofs that do not require a single aggregate STARK + /// proof of the full program execution. For a single STARK proof, use the + /// [`prove`](Self::prove) method instead. + /// + /// Creates an app prover instance specific to the provided exe. + /// This function will generate the [AppProvingKey] if it doesn't already exist and use it to + /// construct the [AppProver]. + pub fn app_prover( + &self, + exe: impl Into, + ) -> Result, SdkError> { + let exe = self.convert_to_exe(exe)?; + let app_pk = self.app_pk(); + let prover = AppProver::::new(self.app_vm_builder.clone(), &app_pk.app_vm_pk, exe)?; + Ok(prover) + } + + /// Constructs a new [StarkProver] instance for the given executable. + /// This function will generate the [AppProvingKey] if it does not already + /// exist. + pub fn prover( + &self, + app_exe: impl Into, + ) -> Result, SdkError> { + let app_exe = self.convert_to_exe(app_exe)?; + let app_pk = self.app_pk(); + let stark_prover = StarkProver::::new( + self.app_vm_builder.clone(), + &app_pk.app_vm_pk, + app_exe, + self.agg_prover(), + self.def_path_prover.clone(), + )?; + Ok(stark_prover) + } + + #[cfg(feature = "root-prover")] + /// Constructs an [`EvmProver`] for the given executable with only the root prover, generating + /// prerequisite keys, lazily + pub fn evm_prover_without_halo2( + &self, + app_exe: impl Into, + ) -> Result, SdkError> { + let app_exe = self.convert_to_exe(app_exe)?; + let app_pk = self.app_pk(); + let evm_prover = EvmProver::::new( + self.app_vm_builder.clone(), + &app_pk.app_vm_pk, + app_exe, + self.agg_prover(), + self.def_path_prover.clone(), + self.root_prover(), + #[cfg(feature = "evm-prove")] + None, + )?; + Ok(evm_prover) + } + + #[cfg(feature = "root-prover")] + /// Constructs an [`EvmProver`] for the given executable, generating prerequisite keys lazily. + pub fn evm_prover( + &self, + app_exe: impl Into, + ) -> Result, SdkError> { + #[allow(unused_mut)] + let mut evm_prover = self.evm_prover_without_halo2(app_exe)?; + #[cfg(feature = "evm-prove")] + { + evm_prover.halo2_prover = Some(self.halo2_prover()); + } + Ok(evm_prover) + } + + // ===================== Component Prover Constructors ===================== + + /// Returns the cached aggregation prover, generating it on first use if needed. + pub fn agg_prover(&self) -> Arc { + let app_pk = self.app_pk(); + self.agg_prover + .get_or_init(|| { + Arc::new(AggProver::new( + Arc::new(app_pk.app_vm_pk.vm_pk.get_vk()), + self.agg_config.clone(), + self.agg_tree_config, + self.def_hook_cached_commit(), + )) + }) + .clone() + } + + #[cfg(feature = "root-prover")] + /// Returns the cached root prover, generating it on first use if needed. + pub fn root_prover(&self) -> Arc { + self.root_prover + .get_or_init(|| { + let system_config = self.app_config.app_vm_config.as_ref(); + let root_params = self.root_params.clone(); + let app_pk = self.app_pk(); + let agg_prover = self.agg_prover(); + + let (trace_heights, root_pk) = compute_root_proof_heights::( + self.app_vm_builder.clone(), + &app_pk.app_vm_pk, + agg_prover.clone(), + root_params.clone(), + self.def_path_prover.clone(), + ) + .expect("Trace heights did not generate properly"); + + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + + Arc::new(RootProver::from_pk( + agg_prover.internal_recursive_prover.get_vk(), + agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap() + .commitment + .into(), + root_pk, + memory_dimensions, + num_user_pvs, + self.def_hook_commit(), + Some(trace_heights), + )) + }) + .clone() + } + + #[cfg(feature = "evm-prove")] + /// Returns the cached Halo2 prover, generating it on first use if needed. + pub fn halo2_prover(&self) -> Halo2Prover { + self.halo2_prover + .get_or_init(|| { + use crate::keygen::static_verifier::keygen_halo2; + + let root_prover = self.root_prover(); + let root_vk = root_prover.0.get_vk().as_ref().clone(); + let agg_prover = self.agg_prover(); + + // Generate a dummy root proof by running a trivial program through the pipeline + let dummy_root_proof = keygen::dummy::generate_dummy_root_proof::( + self.app_vm_builder.clone(), + &self.app_pk().app_vm_pk, + agg_prover.clone(), + self.def_path_prover.clone(), + root_prover, + ); + + let halo2_pk = keygen_halo2( + &self.halo2_config, + &self.halo2_params_reader, + self.halo2_shape, + &agg_prover.internal_recursive_prover.get_vk(), + &root_vk, + &dummy_root_proof, + ); + + Halo2Prover::new(self.halo2_params_reader(), halo2_pk) + }) + .clone() + } + + // ======================== Keygen Related Methods ======================== + + /// Generates the app proving key once and caches it. Future calls will return the cached key. + /// + /// # Panics + /// This function will panic if the app keygen fails. + pub fn app_keygen(&self) -> (AppProvingKey, AppVerifyingKey) { + let pk = self.app_pk().clone(); + let vk = pk.get_app_vk(); + (pk, vk) + } + + /// Generates the app proving key once and caches it. Future calls will return the cached key. + /// + /// # Panics + /// This function will panic if the app keygen fails. + pub fn app_pk(&self) -> &AppProvingKey { + // TODO[jpw]: use `get_or_try_init` once it is stable + self.app_pk.get_or_init(|| { + AppProvingKey::keygen(self.app_config.clone()).expect("app_keygen failed") + }) + } + + /// Returns the app verifying key derived from the cached app proving key. + pub fn app_vk(&self) -> AppVerifyingKey { + self.app_pk().get_app_vk() + } + + /// Generates or retrieves the aggregation proving and verifying keys as a pair. + pub fn agg_keygen(&self) -> (AggProvingKey, MultiStarkVerifyingKey) { + let pk = self.agg_pk(); + let vk = self.agg_vk().as_ref().clone(); + (pk, vk) + } + + /// Generates or retrieves the aggregation prefix proving key without the internal-recursive + /// key. + pub fn agg_prefix_pk(&self) -> AggPrefixProvingKey { + if let Some(agg_prover) = self.agg_prover.get() { + return AggPrefixProvingKey { + leaf: agg_prover.leaf_prover.get_pk(), + internal_for_leaf: agg_prover.internal_for_leaf_prover.get_pk(), + }; + } + + let app_pk = self.app_pk(); + AggProver::keygen_prefix( + Arc::new(app_pk.app_vm_pk.vm_pk.get_vk()), + self.agg_config.clone(), + self.def_hook_cached_commit(), + ) + } + + /// Generates or retrieves the full aggregation proving key. + pub fn agg_pk(&self) -> AggProvingKey { + let agg_prover = self.agg_prover(); + AggProvingKey { + prefix: AggPrefixProvingKey { + leaf: agg_prover.leaf_prover.get_pk(), + internal_for_leaf: agg_prover.internal_for_leaf_prover.get_pk(), + }, + internal_recursive: agg_prover.internal_recursive_prover.get_pk(), + } + } + + /// Returns the aggregation verifying key for the recursive aggregation layer. + pub fn agg_vk(&self) -> Arc> { + self.agg_prover().internal_recursive_prover.get_vk() + } + + #[cfg(feature = "root-prover")] + /// Generates or retrieves the root proving key and recorded trace heights. + pub fn root_pk(&self) -> RootProvingKey { + let root_prover = self.root_prover(); + RootProvingKey { + root_pk: root_prover.0.get_pk(), + trace_heights: root_prover.0.get_trace_heights().unwrap_or_default(), + } + } + + /// Generates the Halo2 (static verifier + wrapper) proving key once and caches it. + /// + /// The flow: + /// 1. Get the root VK and internal recursive VK cached commit + /// 2. Generate a dummy root proof via the EVM prover pipeline + /// 3. Keygen the static verifier circuit + /// 4. Generate a dummy snark from the verifier + /// 5. Keygen the wrapper circuit (auto-tuned or fixed k) + #[cfg(feature = "evm-prove")] + pub fn halo2_pk(&self) -> Halo2ProvingKey { + self.halo2_prover().pk() + } + + /// Generates the [`AppExecutionCommit`] for the given executable. + /// + /// This function will generate the app_pk if it does not already exist. + pub fn app_commit( + &self, + app_exe: impl Into, + ) -> Result { + let prover = self.prover(app_exe)?; + Ok(AppExecutionCommit { + app_exe_commit: CommitBytes::from(prover.generate_baseline().app_exe_commit), + app_vm_commit: CommitBytes::from(prover.app_vm_commit()), + }) + } + + // ======================== Verification Methods ======================== + + /// Verifies aggregate STARK proof of VM execution. + /// + /// **Note**: This function does not have any reliance on `self` and does not depend on the app + /// config set in the [Sdk]. + pub fn verify_proof( + agg_vk: MultiStarkVerifyingKey, + baseline: VerificationBaseline, + proof: &VmStarkProof, + ) -> Result<(), SdkError> { + let vk = VmStarkVerifyingKey { + mvk: agg_vk, + baseline, + }; + verify_vm_stark_proof_decoded(&vk, proof)?; + Ok(()) + } + + #[cfg(feature = "evm-verify")] + /// Generates Solidity verifier artifacts for the cached Halo2 proving key. + pub fn generate_halo2_verifier_solidity(&self) -> Result { + solidity::generate_halo2_verifier_solidity(&self.halo2_pk(), &self.halo2_params_reader) + } + + #[cfg(feature = "evm-verify")] + /// Uses the `verify(..)` interface of the `OpenVmHalo2Verifier` contract. + /// + /// Requires the `evm-verify` feature. Internally deploys the verifier bytecode in a local EVM + /// and executes the verification call. If expected_app_commit is provided, it will check the + /// proof's app_commit against it. + pub fn verify_evm_halo2_proof( + openvm_verifier: &types::EvmHalo2Verifier, + evm_proof: types::EvmProof, + expected_app_commit: Option, + ) -> Result { + if let Some(expected_app_commit) = expected_app_commit { + if expected_app_commit != evm_proof.app_commit { + return Err( + eyre::eyre!("EVM proof verification failed: mismatching app commits").into(), + ); + } + } + solidity::verify_evm_halo2_proof(openvm_verifier, evm_proof) + } +} diff --git a/patches/openvm-sdk/src/prover/agg.rs b/patches/openvm-sdk/src/prover/agg.rs new file mode 100644 index 00000000..a63a5346 --- /dev/null +++ b/patches/openvm-sdk/src/prover/agg.rs @@ -0,0 +1,484 @@ +use std::sync::Arc; + +use eyre::Result; +use itertools::Itertools; +use openvm_circuit::arch::ContinuationVmProof; +use openvm_continuations::{circuit::inner::ProofsType, prover::ChildVkKind}; +use openvm_recursion_circuit::{prelude::Digest, utils::poseidon2_hash_slice}; +use openvm_stark_backend::{ + codec::{Decode, Encode}, + keygen::types::MultiStarkVerifyingKey, + p3_field::PrimeCharacteristicRing, + proof::Proof, +}; +use openvm_stark_sdk::config::baby_bear_poseidon2::{poseidon2_compress_with_capacity, F}; +use openvm_verify_stark_host::{pvs::DeferralPvs, VmStarkProof}; +use tracing::info_span; + +use crate::{ + config::{ + AggregationConfig, AggregationTreeConfig, MAX_NUM_CHILDREN_INTERNAL, MAX_NUM_CHILDREN_LEAF, + }, + keygen::{AggPrefixProvingKey, AggProvingKey}, + prover::deferral::DeferralProof, + SC, +}; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_continuations::prover::InnerGpuProver as InnerAggregationProver; + type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; + } else { + use openvm_continuations::prover::InnerCpuProver as InnerAggregationProver; + type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; + } +} + +pub struct AggProver { + pub leaf_prover: InnerAggregationProver, + pub internal_for_leaf_prover: InnerAggregationProver, + pub internal_recursive_prover: InnerAggregationProver, + pub agg_tree_config: AggregationTreeConfig, +} + +#[derive(Clone)] +pub struct InternalLayerMetadata { + pub internal_recursive_layer: u32, + pub internal_node_idx: u32, + pub proofs_type: ProofsType, +} + +impl AggProver { + pub fn keygen_prefix( + app_or_def_vk: Arc>, + agg_config: AggregationConfig, + def_hook_cached_commit: Option, + ) -> AggPrefixProvingKey { + let leaf_prover = InnerAggregationProver::::new::( + app_or_def_vk, + agg_config.params.leaf.clone(), + false, + def_hook_cached_commit, + ); + let internal_for_leaf_prover = InnerAggregationProver::::new::( + leaf_prover.get_vk(), + agg_config.params.internal, + false, + def_hook_cached_commit, + ); + AggPrefixProvingKey { + leaf: leaf_prover.get_pk(), + internal_for_leaf: internal_for_leaf_prover.get_pk(), + } + } + + #[tracing::instrument(level = "info", fields(group = "agg_keygen"), skip_all)] + pub fn new( + app_or_def_vk: Arc>, + agg_config: AggregationConfig, + agg_tree_config: AggregationTreeConfig, + def_hook_cached_commit: Option, + ) -> Self { + assert!(agg_tree_config.num_children_leaf <= MAX_NUM_CHILDREN_LEAF); + assert!(agg_tree_config.num_children_internal <= MAX_NUM_CHILDREN_INTERNAL); + let leaf_prover = InnerAggregationProver::new::( + app_or_def_vk, + agg_config.params.leaf.clone(), + false, + def_hook_cached_commit, + ); + let internal_for_leaf_prover = InnerAggregationProver::new::( + leaf_prover.get_vk(), + agg_config.params.internal.clone(), + false, + def_hook_cached_commit, + ); + let internal_recursive_prover = InnerAggregationProver::new::( + internal_for_leaf_prover.get_vk(), + agg_config.params.internal.clone(), + true, + def_hook_cached_commit, + ); + Self { + leaf_prover, + internal_for_leaf_prover, + internal_recursive_prover, + agg_tree_config, + } + } + + pub fn from_pk( + app_or_def_vk: Arc>, + agg_pk: AggProvingKey, + agg_tree_config: AggregationTreeConfig, + def_hook_cached_commit: Option, + ) -> Self { + let leaf_prover = InnerAggregationProver::from_pk::( + app_or_def_vk, + agg_pk.prefix.leaf, + false, + def_hook_cached_commit, + ); + let internal_for_leaf_prover = InnerAggregationProver::from_pk::( + leaf_prover.get_vk(), + agg_pk.prefix.internal_for_leaf, + false, + def_hook_cached_commit, + ); + let internal_recursive_prover = InnerAggregationProver::from_pk::( + internal_for_leaf_prover.get_vk(), + agg_pk.internal_recursive, + true, + def_hook_cached_commit, + ); + Self { + leaf_prover, + internal_for_leaf_prover, + internal_recursive_prover, + agg_tree_config, + } + } + + pub fn vm_or_hook_commit(&self) -> Digest { + let app_or_def_vk_commit = self.leaf_prover.get_vk_commit(false); + let leaf_vk_commit = self.internal_for_leaf_prover.get_vk_commit(false); + let internal_for_leaf_vk_commit = self.internal_recursive_prover.get_vk_commit(false); + let components = vec![ + app_or_def_vk_commit.cached_commit, + app_or_def_vk_commit.vk_pre_hash, + leaf_vk_commit.cached_commit, + leaf_vk_commit.vk_pre_hash, + internal_for_leaf_vk_commit.cached_commit, + internal_for_leaf_vk_commit.vk_pre_hash, + ] + .into_flattened(); + poseidon2_hash_slice(&components).0 + } + + pub fn prove_vm( + &self, + continuation_proof: ContinuationVmProof, + ) -> Result<(VmStarkProof, InternalLayerMetadata)> { + // Verify app-layer proofs and generate leaf-layer proofs + let leaf_proofs = info_span!("agg_layer", group = "leaf").in_scope(|| { + continuation_proof + .per_segment + .chunks(self.agg_tree_config.num_children_leaf) + .enumerate() + .map(|(leaf_node_idx, proofs)| { + info_span!("single_leaf_agg", idx = leaf_node_idx).in_scope(|| { + self.leaf_prover + .agg_prove_no_def::(proofs, ChildVkKind::App) + }) + }) + .collect::>>() + })?; + + // Verify leaf-layer proofs and generate internal-for-leaf-layer proofs + let mut internal_node_idx = -1; + let mut internal_proofs = + info_span!("agg_layer", group = "internal_for_leaf").in_scope(|| { + leaf_proofs + .chunks(self.agg_tree_config.num_children_internal) + .map(|proofs| { + internal_node_idx += 1; + info_span!("single_internal_agg", idx = internal_node_idx).in_scope(|| { + self.internal_for_leaf_prover + .agg_prove_no_def::(proofs, ChildVkKind::Standard) + }) + }) + .collect::>>() + })?; + + // Verify internal-for-leaf-layer proofs and generate internal-recursive-layer proofs + internal_proofs = + info_span!("agg_layer", group = "internal_recursive.0").in_scope(|| { + internal_proofs + .chunks(self.agg_tree_config.num_children_internal) + .map(|proofs| { + internal_node_idx += 1; + info_span!("single_internal_agg", idx = internal_node_idx).in_scope(|| { + self.internal_recursive_prover + .agg_prove_no_def::(proofs, ChildVkKind::Standard) + }) + }) + .collect::>>() + })?; + + // Recursively verify internal-layer proofs until only 1 remains + let mut internal_recursive_layer = 1; + while internal_proofs.len() > 1 { + internal_proofs = info_span!( + "agg_layer", + group = format!("internal_recursive.{internal_recursive_layer}") + ) + .in_scope(|| { + internal_proofs + .chunks(self.agg_tree_config.num_children_internal) + .map(|proofs| { + internal_node_idx += 1; + info_span!("single_internal_agg", idx = internal_node_idx).in_scope(|| { + self.internal_recursive_prover + .agg_prove_no_def::(proofs, ChildVkKind::RecursiveSelf) + }) + }) + .collect::>>() + })?; + internal_recursive_layer += 1; + } + + Ok(( + VmStarkProof { + inner: internal_proofs.pop().unwrap(), + user_pvs_proof: continuation_proof.user_public_values, + deferral_merkle_proofs: None, + }, + InternalLayerMetadata { + internal_recursive_layer: internal_recursive_layer as u32, + internal_node_idx: internal_node_idx as u32, + proofs_type: ProofsType::Vm, + }, + )) + } + + pub fn prove_def(&self, input: Vec) -> Result<(DeferralProof, u32)> { + assert!(!input.is_empty()); + assert!(input.len().is_power_of_two()); + + // Leaf round: hook-level → leaf-level + let mut proofs = info_span!("agg_layer", group = "def_leaf") + .in_scope(|| reduce_def_round(input, ChildVkKind::App, &self.leaf_prover))?; + + // Internal-for-leaf round: leaf-level → i4l-level + proofs = info_span!("agg_layer", group = "def_internal_for_leaf").in_scope(|| { + reduce_def_round( + proofs, + ChildVkKind::Standard, + &self.internal_for_leaf_prover, + ) + })?; + + // Internal-recursive round 0: i4l-level → ir-level + proofs = info_span!("agg_layer", group = "def_internal_recursive.0").in_scope(|| { + reduce_def_round( + proofs, + ChildVkKind::Standard, + &self.internal_recursive_prover, + ) + })?; + + // Internal-recursive rounds: ir-level → ir-level until single proof remains + let mut layer = 1; + while proofs.len() > 1 { + proofs = info_span!( + "agg_layer", + group = format!("def_internal_recursive.{layer}") + ) + .in_scope(|| { + reduce_def_round( + proofs, + ChildVkKind::RecursiveSelf, + &self.internal_recursive_prover, + ) + })?; + layer += 1; + } + + Ok((proofs.pop().unwrap(), layer)) + } + + pub fn prove_mixed( + &self, + mut vm_proof: VmStarkProof, + def_proof: DeferralProof, + metadata: &mut InternalLayerMetadata, + mut def_internal_recursive_layer: u32, + ) -> Result { + let DeferralProof::Present(mut def_inner) = def_proof else { + return Ok(vm_proof); + }; + + // Aggregation requires equal child recursion_depth values, so we wrap the + // shallower side until both proofs are at the same internal-recursive depth. + while metadata.internal_recursive_layer < def_internal_recursive_layer { + vm_proof = self.wrap_proof(vm_proof, metadata)?; + } + while def_internal_recursive_layer < metadata.internal_recursive_layer { + def_inner = self.wrap_def_inner(def_inner, def_internal_recursive_layer)?; + def_internal_recursive_layer += 1; + } + + vm_proof.inner = info_span!( + "agg_layer", + group = format!("internal_recursive.{}", metadata.internal_recursive_layer) + ) + .in_scope(|| { + metadata.internal_recursive_layer += 1; + info_span!("single_internal_agg", idx = metadata.internal_node_idx).in_scope(|| { + metadata.internal_node_idx += 1; + self.internal_recursive_prover.agg_prove::( + &[vm_proof.inner, def_inner], + ChildVkKind::RecursiveSelf, + ProofsType::Mix, + None, + ) + }) + })?; + + metadata.proofs_type = ProofsType::Combined; + Ok(vm_proof) + } + + pub fn wrap_proof( + &self, + mut proof: VmStarkProof, + metadata: &mut InternalLayerMetadata, + ) -> Result { + proof.inner = info_span!( + "agg_layer", + group = format!("internal_recursive.{}", metadata.internal_recursive_layer) + ) + .in_scope(|| { + metadata.internal_recursive_layer += 1; + info_span!("single_internal_agg", idx = metadata.internal_node_idx).in_scope(|| { + metadata.internal_node_idx += 1; + self.internal_recursive_prover.agg_prove::( + &[proof.inner], + ChildVkKind::RecursiveSelf, + metadata.proofs_type, + None, + ) + }) + })?; + Ok(proof) + } + + pub(crate) fn wrap_def_inner( + &self, + mut proof: Proof, + def_internal_recursive_layer: u32, + ) -> Result> { + proof = info_span!( + "agg_layer", + group = format!("def_internal_recursive.{def_internal_recursive_layer}") + ) + .in_scope(|| { + self.internal_recursive_prover.agg_prove::( + &[proof], + ChildVkKind::RecursiveSelf, + ProofsType::Deferral, + None, + ) + })?; + Ok(proof) + } +} + +fn reduce_def_round( + proofs: Vec, + kind: ChildVkKind, + prover: &InnerAggregationProver, +) -> Result> { + if proofs.len() == 1 { + // A singleton round can only happen when the entire round has one present input proof. + let DeferralProof::Present(p) = proofs.into_iter().next().unwrap() else { + panic!("singleton deferral round must contain a present proof"); + }; + return Ok(vec![DeferralProof::Present(prover.agg_prove::( + &[p], + kind, + ProofsType::Deferral, + None, + )?)]); + } + + assert!( + proofs.len().is_multiple_of(2), + "non-singleton deferral round must have an even number of proofs" + ); + + let mut next = Vec::with_capacity(proofs.len() / 2); + for (a, b) in proofs.into_iter().tuples() { + let combined = match (a, b) { + (DeferralProof::Present(p0), DeferralProof::Present(p1)) => DeferralProof::Present( + prover.agg_prove::(&[p0, p1], kind, ProofsType::Deferral, None)?, + ), + (DeferralProof::Present(p), DeferralProof::Absent(pvs)) => { + // Absent is the right child (present is left, is_right = false) + DeferralProof::Present(prover.agg_prove::( + &[p], + kind, + ProofsType::Deferral, + Some((pvs, false)), + )?) + } + (DeferralProof::Absent(pvs), DeferralProof::Present(p)) => { + // Absent is the left child (present is right, is_right = true) + DeferralProof::Present(prover.agg_prove::( + &[p], + kind, + ProofsType::Deferral, + Some((pvs, true)), + )?) + } + (DeferralProof::Absent(pvs0), DeferralProof::Absent(pvs1)) => { + debug_assert_eq!(pvs0.depth, pvs1.depth); + debug_assert_eq!(pvs0.node_idx + F::ONE, pvs1.node_idx); + DeferralProof::Absent(DeferralPvs { + initial_acc_hash: poseidon2_compress_with_capacity( + pvs0.initial_acc_hash, + pvs1.initial_acc_hash, + ) + .0, + final_acc_hash: poseidon2_compress_with_capacity( + pvs0.final_acc_hash, + pvs1.final_acc_hash, + ) + .0, + depth: pvs0.depth + F::ONE, + node_idx: pvs0.node_idx.halve(), + }) + } + }; + next.push(combined); + } + Ok(next) +} + +impl Encode for InternalLayerMetadata { + fn encode(&self, writer: &mut W) -> std::io::Result<()> { + self.internal_recursive_layer.encode(writer)?; + self.internal_node_idx.encode(writer)?; + let proofs_type_byte: u8 = match self.proofs_type { + ProofsType::Vm => 0, + ProofsType::Deferral => 1, + ProofsType::Mix => 2, + ProofsType::Combined => 3, + }; + proofs_type_byte.encode(writer) + } +} + +impl Decode for InternalLayerMetadata { + fn decode(reader: &mut R) -> std::io::Result { + let internal_recursive_layer = u32::decode(reader)?; + let internal_node_idx = u32::decode(reader)?; + let proofs_type = match u8::decode(reader)? { + 0 => ProofsType::Vm, + 1 => ProofsType::Deferral, + 2 => ProofsType::Mix, + 3 => ProofsType::Combined, + b => { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("invalid ProofsType byte: {b}"), + )) + } + }; + Ok(Self { + internal_recursive_layer, + internal_node_idx, + proofs_type, + }) + } +} diff --git a/patches/openvm-sdk/src/prover/app.rs b/patches/openvm-sdk/src/prover/app.rs new file mode 100644 index 00000000..54fef6ed --- /dev/null +++ b/patches/openvm-sdk/src/prover/app.rs @@ -0,0 +1,209 @@ +use std::sync::{Arc, OnceLock}; + +use getset::Getters; +use openvm_circuit::{ + arch::{ + hasher::poseidon2::{vm_poseidon2_hasher, Poseidon2Hasher}, + instructions::exe::VmExe, + verify_segments, ContinuationVmProof, ContinuationVmProver, Executor, MeteredExecutor, + PreflightExecutor, VerifiedExecutionPayload, VirtualMachine, VirtualMachineError, + VmBuilder, VmExecutionConfig, VmInstance, VmVerificationError, + }, + system::{ + memory::dimensions::MemoryDimensions, program::trace::compute_exe_commit_from_mem_config, + }, +}; +use openvm_stark_backend::{ + keygen::types::MultiStarkVerifyingKey, p3_field::PrimeField32, prover::ProverBackend, + StarkEngine, Val, +}; +use openvm_stark_sdk::config::baby_bear_poseidon2::Digest; +use tracing::instrument; + +use crate::{ + keygen::AppVerifyingKey, + prover::vm::{new_local_prover, types::VmProvingKey}, + util::check_max_constraint_degrees, + SdkError, StdIn, F, SC, +}; + +#[derive(Getters)] +pub struct AppProver +where + E: StarkEngine, + VB: VmBuilder, +{ + pub program_name: Option, + #[getset(get = "pub")] + instance: VmInstance, + #[getset(get = "pub")] + app_vm_vk: MultiStarkVerifyingKey, + app_exe_commit: OnceLock, +} + +impl AppProver +where + E: StarkEngine, + VB: VmBuilder, + Val: PrimeField32, +{ + /// Creates a new [AppProver] instance. This method will re-commit the `exe` program on device. + /// If a cached version of the program already exists on device, then directly use the + /// [`Self::new_from_instance`] constructor. + /// + /// The `leaf_verifier_program_commit` is the commitment to the program of the leaf verifier + /// that verifies the App VM circuit. It can be found in the `AppProvingKey`. + pub fn new( + vm_builder: VB, + app_vm_pk: &VmProvingKey, + app_exe: Arc>>, + ) -> Result { + let instance = new_local_prover(vm_builder, app_vm_pk, app_exe)?; + let app_vm_vk = app_vm_pk.vm_pk.get_vk(); + Ok(Self::new_from_instance(instance, app_vm_vk)) + } + + pub fn new_from_instance( + instance: VmInstance, + app_vm_vk: MultiStarkVerifyingKey, + ) -> Self { + Self { + program_name: None, + instance, + app_vm_vk, + app_exe_commit: OnceLock::new(), + } + } + + pub fn set_program_name(&mut self, program_name: impl AsRef) -> &mut Self { + self.program_name = Some(program_name.as_ref().to_string()); + self + } + + pub fn with_program_name(mut self, program_name: impl AsRef) -> Self { + self.set_program_name(program_name); + self + } + + pub fn app_program_commit(&self) -> ::Commitment { + *self.instance().program_commitment() + } + + /// Returns commitment to the executable + pub fn app_exe_commit(&self) -> Digest { + *self.app_exe_commit.get_or_init(|| { + compute_exe_commit_from_mem_config( + &self.app_program_commit(), + self.instance.exe(), + &self.instance.vm.config().as_ref().memory_config, + ) + }) + } + + pub fn memory_dimensions(&self) -> MemoryDimensions { + self.instance + .vm + .config() + .as_ref() + .memory_config + .memory_dimensions() + } + + pub fn num_user_pvs(&self) -> usize { + self.instance.vm.config().as_ref().num_public_values + } + + /// Generates proof for every continuation segment + #[instrument( + name = "app_prove", + skip_all, + fields(group = self.program_name.as_ref().unwrap_or(&"app_proof".to_string())) + )] + pub fn prove( + &mut self, + input: StdIn>, + ) -> Result, VirtualMachineError> + where + >>::Executor: Executor> + + MeteredExecutor> + + PreflightExecutor, VB::RecordArena>, + { + check_max_constraint_degrees( + self.vm_config().as_ref(), + self.app_vm_vk.inner.max_constraint_degree(), + ); + let proof = ContinuationVmProver::prove(&mut self.instance, input)?; + #[cfg(debug_assertions)] + let _ = verify_app_proof_inner::( + &self.app_vm_vk, + self.memory_dimensions(), + self.num_user_pvs(), + &proof, + ) + .expect("app proof verification failed"); + Ok(proof) + } + + /// App Exe + pub fn exe(&self) -> Arc>> { + self.instance.exe().clone() + } + + /// App VM + pub fn vm(&self) -> &VirtualMachine { + &self.instance.vm + } + + /// App VM config + pub fn vm_config(&self) -> &VB::VmConfig { + self.instance.vm.config() + } +} + +/// Verifies a ContinuationVmProof and returns the app_exe_commit +pub fn verify_app_proof>( + app_vk: &AppVerifyingKey, + proof: &ContinuationVmProof, +) -> Result { + verify_app_proof_inner::( + &app_vk.vk, + app_vk.memory_dimensions, + app_vk.num_user_pvs, + proof, + ) +} + +/// Verifies a ContinuationVmProof from the borrowed components of an +/// [`AppVerifyingKey`], returning the app_exe_commit. +fn verify_app_proof_inner>( + vk: &MultiStarkVerifyingKey, + memory_dimensions: MemoryDimensions, + num_user_pvs: usize, + proof: &ContinuationVmProof, +) -> Result { + static POSEIDON2_HASHER: OnceLock> = OnceLock::new(); + let engine = E::new(vk.inner.params.clone()); + let VerifiedExecutionPayload { + exe_commit, + final_memory_root, + } = verify_segments(&engine, vk, &proof.per_segment)?; + + if proof.user_public_values.public_values.len() != num_user_pvs { + return Err(SdkError::Other(eyre::eyre!( + "wrong number of user public values (expected: {}, actual: {})", + num_user_pvs, + proof.user_public_values.public_values.len() + ))); + } + + proof + .user_public_values + .verify( + POSEIDON2_HASHER.get_or_init(vm_poseidon2_hasher), + memory_dimensions, + final_memory_root, + ) + .map_err(VmVerificationError::from)?; + + Ok(exe_commit) +} diff --git a/patches/openvm-sdk/src/prover/deferral/circuit.rs b/patches/openvm-sdk/src/prover/deferral/circuit.rs new file mode 100644 index 00000000..8c4890e9 --- /dev/null +++ b/patches/openvm-sdk/src/prover/deferral/circuit.rs @@ -0,0 +1,162 @@ +use std::{borrow::Borrow, iter::once, sync::Arc}; + +use eyre::Result; +use itertools::Itertools; +use openvm_continuations::{ + circuit::deferral::{hook::DeferralIoCommit, DeferralCircuitPvs, DEF_CIRCUIT_PVS_AIR_ID}, + prover::{DeferralChildVkKind, DeferralCircuitProver}, + SC, +}; +use openvm_recursion_circuit::utils::poseidon2_hash_slice; +use openvm_stark_backend::{keygen::types::MultiStarkProvingKey, proof::Proof, SystemParams}; +use openvm_stark_sdk::config::baby_bear_poseidon2::{Digest, F}; +use openvm_verify_stark_host::pvs::VkCommit; +use tracing::info_span; + +use crate::DeferralInput; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_continuations::prover::DeferralInnerGpuProver as DeferralInnerProver; + type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; + } else { + use openvm_continuations::prover::DeferralInnerCpuProver as DeferralInnerProver; + type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; + } +} + +pub struct SingleDefCircuitProver { + pub def_circuit_prover: Box + Send + Sync>, + pub leaf_prover: DeferralInnerProver, + pub internal_for_leaf_prover: DeferralInnerProver, +} + +pub struct SingleDefCircuitResult { + pub internal_for_leaf_proofs: Vec>, + pub leaf_io_commits: Vec>, +} + +impl SingleDefCircuitProver { + pub fn new + Send + Sync + 'static>( + def_circuit_prover: DP, + leaf_params: SystemParams, + internal_params: SystemParams, + ) -> Self { + let leaf_prover = + DeferralInnerProver::new::(def_circuit_prover.get_vk(), leaf_params, false); + let internal_for_leaf_prover = + DeferralInnerProver::new::(leaf_prover.get_vk(), internal_params, false); + Self { + def_circuit_prover: Box::new(def_circuit_prover), + leaf_prover, + internal_for_leaf_prover, + } + } + + pub fn from_pks + Send + Sync + 'static>( + def_circuit_prover: DP, + leaf_pk: Arc>, + internal_for_leaf_pk: Arc>, + ) -> Self { + let leaf_prover = + DeferralInnerProver::from_pk::(def_circuit_prover.get_vk(), leaf_pk, false); + let internal_for_leaf_prover = + DeferralInnerProver::from_pk::(leaf_prover.get_vk(), internal_for_leaf_pk, false); + Self { + def_circuit_prover: Box::new(def_circuit_prover), + leaf_prover, + internal_for_leaf_prover, + } + } + + pub fn prove(&self, inputs: &DeferralInput) -> Result { + // Generate deferral circuit proofs + let def_proofs = inputs + .byte_vec + .iter() + .map(|input| self.def_circuit_prover.prove(input)) + .collect_vec(); + + // Extract leaf IO commits from the deferral circuit proofs + let leaf_io_commits = def_proofs + .iter() + .map(|proof| { + let pvs: &DeferralCircuitPvs = proof.public_values[DEF_CIRCUIT_PVS_AIR_ID] + .as_slice() + .borrow(); + let commit_values = once(pvs.input_commit) + .chain( + proof + .trace_vdata + .iter() + .flatten() + .flat_map(|vdata| vdata.cached_commitments.iter().copied()), + ) + .flatten() + .collect_vec(); + let folded_input_commit = poseidon2_hash_slice(&commit_values).0; + (folded_input_commit, pvs.output_commit) + }) + .collect(); + + // Verify def-layer proofs and generate leaf-layer proofs + let child_merkle_depth = (def_proofs.len() != 1).then_some(0); + let leaf_proofs = info_span!("agg_layer", group = "def_leaf").in_scope(|| { + def_proofs + .chunks(2) + .enumerate() + .map(|(leaf_node_idx, proofs)| { + info_span!("single_leaf_agg", idx = leaf_node_idx).in_scope(|| { + self.leaf_prover.agg_prove::( + proofs, + DeferralChildVkKind::DeferralCircuit, + child_merkle_depth, + ) + }) + }) + .collect::>>() + })?; + + // Verify leaf-layer proofs and generate internal-for-leaf-layer proofs + let mut internal_node_idx = 0u32; + let child_merkle_depth = (leaf_proofs.len() != 1).then_some(1); + let internal_for_leaf_proofs = info_span!("agg_layer", group = "internal_for_leaf") + .in_scope(|| { + leaf_proofs + .chunks(2) + .map(|proofs| { + let ret = info_span!("single_internal_agg", idx = internal_node_idx) + .in_scope(|| { + self.internal_for_leaf_prover.agg_prove::( + proofs, + DeferralChildVkKind::DeferralAggregation, + child_merkle_depth, + ) + }); + internal_node_idx += 1; + ret + }) + .collect::>>() + })?; + + Ok(SingleDefCircuitResult { + internal_for_leaf_proofs, + leaf_io_commits, + }) + } + + pub fn circuit_commit(&self, internal_for_leaf_vk_commit: VkCommit) -> Digest { + let def_vk_commit = self.leaf_prover.get_vk_commit(false); + let leaf_vk_commit = self.internal_for_leaf_prover.get_vk_commit(false); + + let vk_commit_components = vec![ + def_vk_commit.cached_commit, + def_vk_commit.vk_pre_hash, + leaf_vk_commit.cached_commit, + leaf_vk_commit.vk_pre_hash, + internal_for_leaf_vk_commit.cached_commit, + internal_for_leaf_vk_commit.vk_pre_hash, + ]; + poseidon2_hash_slice(&vk_commit_components.into_flattened()).0 + } +} diff --git a/patches/openvm-sdk/src/prover/deferral/merkle.rs b/patches/openvm-sdk/src/prover/deferral/merkle.rs new file mode 100644 index 00000000..2a13f752 --- /dev/null +++ b/patches/openvm-sdk/src/prover/deferral/merkle.rs @@ -0,0 +1,65 @@ +use openvm_circuit::{ + arch::instructions::DEFERRAL_AS, + system::memory::{dimensions::MemoryDimensions, merkle::MerkleTree}, +}; +use openvm_stark_backend::p3_field::PrimeCharacteristicRing; +use openvm_stark_sdk::config::baby_bear_poseidon2::{DIGEST_SIZE, F}; +use openvm_verify_stark_host::deferral::DeferralMerkleProofs; + +/// Compute deferral merkle proofs from the initial and final memory merkle trees. +/// +/// Proofs have length `overall_height()`. When `depth > 0`, the first `depth` entries +/// are zeros (skipped levels covered by the deferral subtree). The final deferral +/// subtree is required by the verifier to be rooted at node_idx 0. +pub fn compute_deferral_merkle_proofs( + memory_dimensions: MemoryDimensions, + initial_merkle_tree: &MerkleTree, + final_merkle_tree: &MerkleTree, + depth: usize, +) -> DeferralMerkleProofs { + let initial_merkle_proof = + deferral_merkle_proof_from_tree(memory_dimensions, initial_merkle_tree, depth); + let final_merkle_proof = + deferral_merkle_proof_from_tree(memory_dimensions, final_merkle_tree, depth); + DeferralMerkleProofs { + initial_merkle_proof, + final_merkle_proof, + } +} + +/// Extract one side of the deferral merkle proof from a memory merkle tree. +/// +/// Returns a full-length proof (`overall_height()` entries). The first `depth` entries +/// are zeros; the remaining entries are siblings from the tree. +fn deferral_merkle_proof_from_tree( + memory_dimensions: MemoryDimensions, + merkle_tree: &MerkleTree, + depth: usize, +) -> Vec<[F; DIGEST_SIZE]> { + let overall_height = memory_dimensions.overall_height(); + + // Leaf index for DEFERRAL_AS, block_id=0 in the full tree (1-indexed). + let leaf_idx = (1u64 << overall_height) + memory_dimensions.label_to_index((DEFERRAL_AS, 0)); + debug_assert_eq!(leaf_idx % 2, 0); + + // Start at level `depth` above the leaf. When `depth == 0`, the first node in the + // path is the right sibling of the node at `leaf_idx`. + let mut node_idx = if depth == 0 { + leaf_idx + 1 + } else { + leaf_idx >> depth + }; + + // Pad the first `depth` entries with zeros (skipped levels). + let mut proof = vec![[F::ZERO; DIGEST_SIZE]; depth]; + + // Collect siblings from depth up to the root. + while node_idx > 1 { + let sibling_idx = node_idx ^ 1; + proof.push(merkle_tree.get_node(sibling_idx)); + node_idx >>= 1; + } + + assert_eq!(proof.len(), overall_height); + proof +} diff --git a/patches/openvm-sdk/src/prover/deferral/mod.rs b/patches/openvm-sdk/src/prover/deferral/mod.rs new file mode 100644 index 00000000..0caea5e9 --- /dev/null +++ b/patches/openvm-sdk/src/prover/deferral/mod.rs @@ -0,0 +1,264 @@ +use std::sync::Arc; + +use eyre::Result; +use itertools::Itertools; +use openvm_continuations::{ + prover::{DeferralChildVkKind, DeferralCircuitProver}, + CommitBytes, SC, +}; +use openvm_deferral_circuit::{DeferralExtension, DeferralFn}; +use openvm_recursion_circuit::utils::poseidon2_hash_slice; +use openvm_stark_backend::{ + keygen::types::MultiStarkProvingKey, + p3_field::{PrimeCharacteristicRing, PrimeField32}, + proof::Proof, + SystemParams, +}; +use openvm_stark_sdk::config::baby_bear_poseidon2::{ + poseidon2_compress_with_capacity, DIGEST_SIZE, F, +}; +use openvm_verify_stark_host::pvs::DeferralPvs; +use tracing::info_span; + +use crate::{config::AggregationConfig, keygen::AggProvingKey, DeferralInput}; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_continuations::prover::DeferralInnerGpuProver as DeferralInnerProver; + use openvm_continuations::prover::DeferralHookGpuProver as DeferralHookProver; + type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; + } else { + use openvm_continuations::prover::DeferralInnerCpuProver as DeferralInnerProver; + use openvm_continuations::prover::DeferralHookCpuProver as DeferralHookProver; + type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; + } +} + +mod circuit; +mod merkle; +mod verify_stark; +pub use circuit::*; +pub use merkle::*; + +pub type DefAggProvingKey = AggProvingKey; + +#[allow(clippy::large_enum_variant)] +#[derive(Clone)] +pub enum DeferralProof { + Present(Proof), + Absent(DeferralPvs), +} + +pub struct DeferralProver { + pub single_circuit_provers: Vec, + pub internal_recursive_prover: DeferralInnerProver, + pub def_hook_prover: DeferralHookProver, +} + +impl DeferralProver { + pub fn new + Send + Sync + 'static>( + def_circuit_prover: DP, + agg_config: AggregationConfig, + hook_params: SystemParams, + ) -> Self { + assert_eq!(def_circuit_prover.get_def_idx(), 0); + let single_circuit_prover = SingleDefCircuitProver::new( + def_circuit_prover, + agg_config.params.leaf, + agg_config.params.internal.clone(), + ); + let internal_recursive_prover = DeferralInnerProver::new::( + single_circuit_prover.internal_for_leaf_prover.get_vk(), + agg_config.params.internal, + true, + ); + let internal_recursive_cached_commit = internal_recursive_prover + .get_vk_commit(true) + .cached_commit + .into(); + let def_hook_prover = DeferralHookProver::new::( + internal_recursive_prover.get_vk(), + internal_recursive_cached_commit, + hook_params, + ); + Self { + single_circuit_provers: vec![single_circuit_prover], + internal_recursive_prover, + def_hook_prover, + } + } + + pub fn from_pks + Send + Sync + 'static>( + def_circuit_prover: DP, + def_agg_pk: DefAggProvingKey, + def_hook_pk: Arc>, + internal_recursive_cached_commit: CommitBytes, + ) -> Self { + assert_eq!(def_circuit_prover.get_def_idx(), 0); + let single_circuit_prover = SingleDefCircuitProver::from_pks( + def_circuit_prover, + def_agg_pk.prefix.leaf, + def_agg_pk.prefix.internal_for_leaf, + ); + let internal_recursive_prover = DeferralInnerProver::from_pk::( + single_circuit_prover.internal_for_leaf_prover.get_vk(), + def_agg_pk.internal_recursive, + false, + ); + let def_hook_prover = DeferralHookProver::from_pk::( + internal_recursive_prover.get_vk(), + internal_recursive_cached_commit, + def_hook_pk, + ); + Self { + single_circuit_provers: vec![single_circuit_prover], + internal_recursive_prover, + def_hook_prover, + } + } + + pub fn with_prover + Send + Sync + 'static>( + mut self, + def_circuit_prover: DP, + ) -> Self { + assert_eq!( + def_circuit_prover.get_def_idx(), + self.single_circuit_provers.len() + ); + let leaf_params = self.single_circuit_provers[0] + .leaf_prover + .get_vk() + .inner + .params + .clone(); + let internal_params = self.internal_recursive_prover.get_vk().inner.params.clone(); + let single_circuit_prover = + SingleDefCircuitProver::new(def_circuit_prover, leaf_params, internal_params); + self.single_circuit_provers.push(single_circuit_prover); + self + } + + pub fn prove(&self, inputs: &[DeferralInput]) -> Result> { + // Generate internal-for-leaf proofs and leaf IO commits per circuit + let per_circuit = self + .single_circuit_provers + .iter() + .zip_eq(inputs) + .map(|(prover, inputs)| prover.prove(inputs)) + .collect::>>()?; + + // For each circuit: do internal recursive aggregation then generate the hook proof + let mut per_circuit = per_circuit + .into_iter() + .enumerate() + .map(|(def_idx, res)| { + let mut proofs = res.internal_for_leaf_proofs; + if proofs.is_empty() { + let def_circuit_commit = self.single_circuit_provers[def_idx] + .circuit_commit(self.internal_recursive_prover.get_vk_commit(false)); + Ok(DeferralProof::Absent(absent_deferral_pvs( + def_idx, + def_circuit_commit, + ))) + } else { + let mut merkle_depth = 2usize; + let mut layer = 0usize; + + // Aggregate internal-for-leaf proofs down to a single proof. + // First pass uses DeferralAggregation (children are i4l proofs); + // subsequent passes use RecursiveSelf (children are ir proofs). + loop { + let is_first = layer == 0; + let child_merkle_depth = if proofs.len() > 1 { + let d = merkle_depth; + merkle_depth += 1; + Some(d) + } else { + None + }; + + proofs = info_span!( + "agg_layer", + group = format!("internal_recursive.{layer}"), + circuit = def_idx + ) + .in_scope(|| { + proofs + .chunks(2) + .enumerate() + .map(|(idx, chunk)| { + let kind = if is_first { + DeferralChildVkKind::DeferralAggregation + } else { + DeferralChildVkKind::RecursiveSelf + }; + info_span!("single_internal_agg", idx = idx).in_scope(|| { + self.internal_recursive_prover.agg_prove::( + chunk, + kind, + child_merkle_depth, + ) + }) + }) + .collect::>>() + })?; + + layer += 1; + if proofs.len() == 1 { + break; + } + } + + // Generate the deferral hook proof + Ok(DeferralProof::Present( + self.def_hook_prover + .prove::(proofs.pop().unwrap(), res.leaf_io_commits)?, + )) + } + }) + .collect::>>()?; + + // Pad returned vector up to a power of two length with absent deferral proofs + let target_length = per_circuit.len().next_power_of_two(); + for def_idx in per_circuit.len()..target_length { + per_circuit.push(DeferralProof::Absent(absent_deferral_pvs( + def_idx, + [F::ZERO; DIGEST_SIZE], + ))); + } + + Ok(per_circuit) + } + + pub fn make_extension(&self, fns: Vec>) -> DeferralExtension { + let vk_commit = self.internal_recursive_prover.get_vk_commit(false); + let def_circuit_commits = self + .single_circuit_provers + .iter() + .map(|p| { + p.circuit_commit(vk_commit) + .iter() + .flat_map(|f| f.to_unique_u32().to_le_bytes()) + .collect::>() + .try_into() + .unwrap() + }) + .collect(); + DeferralExtension { + fns, + def_circuit_commits, + } + } +} + +fn absent_deferral_pvs(def_idx: usize, def_circuit_commit: [F; DIGEST_SIZE]) -> DeferralPvs { + let input_acc_hash = poseidon2_hash_slice(&def_circuit_commit).0; + let output_acc_hash = poseidon2_hash_slice(&[F::ZERO]).0; + let combined_hash = poseidon2_compress_with_capacity(input_acc_hash, output_acc_hash).0; + DeferralPvs { + initial_acc_hash: combined_hash, + final_acc_hash: combined_hash, + depth: F::ONE, + node_idx: F::from_usize(def_idx), + } +} diff --git a/patches/openvm-sdk/src/prover/deferral/verify_stark.rs b/patches/openvm-sdk/src/prover/deferral/verify_stark.rs new file mode 100644 index 00000000..9409ff64 --- /dev/null +++ b/patches/openvm-sdk/src/prover/deferral/verify_stark.rs @@ -0,0 +1,116 @@ +use std::sync::Arc; + +use openvm_circuit::system::memory::dimensions::MemoryDimensions; +use openvm_continuations::{ + circuit::deferral::dummy::dummy_deferral_circuit_vk, prover::DeferralCircuitProver, SC, +}; +use openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey, proof::Proof, SystemParams}; + +use crate::{ + config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig}, + prover::{AggProver, DeferralPathProver, DeferralProver}, +}; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_verify_stark_circuit::prover::DeferredVerifyGpuProver as VerifyProver; + use openvm_verify_stark_circuit::prover::DeferredVerifyGpuCircuitProver as VerifyCircuitProver; + type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; + } else { + use openvm_verify_stark_circuit::prover::DeferredVerifyCpuProver as VerifyProver; + use openvm_verify_stark_circuit::prover::DeferredVerifyCpuCircuitProver as VerifyCircuitProver; + type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; + } +} + +impl DeferralPathProver { + /// Builds a [`DeferralPathProver`] backed by the verify-stark circuit, configured so an SDK + /// with the given params can recursively verify the VM STARK proofs it produces, including its + /// own deferral-carrying proofs. + /// + /// The deferral-enabled internal-recursive vk and the self-referential `def_hook_commit` are + /// derived internally from a dummy deferral circuit. + pub fn verify_stark( + agg_params: &AggregationSystemParams, + hook_params: SystemParams, + memory_dimensions: MemoryDimensions, + num_user_pvs: usize, + ) -> Self { + // Derive the deferral path's fixed-point artifacts with a cheap dummy deferral circuit. + let dummy = DummyDefCircuitProver { + vk: dummy_deferral_circuit_vk::(agg_params.internal.clone()), + }; + let agg_config = AggregationConfig { + params: agg_params.clone(), + }; + let dummy_deferral_prover = + DeferralProver::new(dummy, agg_config.clone(), hook_params.clone()); + + // Construct the deferral-path AggProver, which can aggregate hook proofs from both the + // dummy DeferralProver above and the verify-stark one below. + let agg_prover = Arc::new(AggProver::new( + dummy_deferral_prover.def_hook_prover.get_vk(), + agg_config.clone(), + AggregationTreeConfig::deferral(), + Some(dummy_deferral_prover.def_hook_prover.get_cached_commit()), + )); + + // The deferral-path aggregation tree's internal-recursive vk is a universal copy of the VM + // internal-recursive vk that a verify-stark circuit verifies. + let ir_vk = agg_prover.internal_recursive_prover.get_vk(); + let ir_cached_commit = agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .expect("internal-recursive prover must expose its self vk pcs data") + .commitment + .into(); + let def_hook_commit = agg_prover.vm_or_hook_commit(); + + // Construct the verify-stark DeferralProver, which should have the same hook vk and cached + // commit as the dummy one. + let deferred_verify_prover = VerifyProver::new::( + ir_vk, + ir_cached_commit, + agg_params.internal.clone(), + memory_dimensions, + num_user_pvs, + Some(def_hook_commit), + 0, + ); + let verify_stark_prover = VerifyCircuitProver::new(deferred_verify_prover); + let deferral_prover = DeferralProver::new(verify_stark_prover, agg_config, hook_params); + + assert_eq!( + deferral_prover.def_hook_prover.get_vk().pre_hash, + dummy_deferral_prover.def_hook_prover.get_vk().pre_hash + ); + assert_eq!( + deferral_prover.def_hook_prover.get_cached_commit(), + dummy_deferral_prover.def_hook_prover.get_cached_commit() + ); + + // Return the deferral-enabled verify-stark DeferralPathProver. + Self::new(Arc::new(deferral_prover), agg_prover) + } +} + +/// A dummy [`DeferralCircuitProver`] that only exposes a trivial verifying key. It exists solely to +/// seed the deferral aggregation chain when deriving the deferral path fixed point; its `prove` +/// method is never called. +struct DummyDefCircuitProver { + vk: Arc>, +} + +impl DeferralCircuitProver for DummyDefCircuitProver { + fn get_vk(&self) -> Arc> { + self.vk.clone() + } + + fn prove(&self, _input_bytes: &[u8]) -> Proof { + unreachable!("DummyDefCircuitProver is only used to derive deferral path artifacts") + } + + fn get_def_idx(&self) -> usize { + 0 + } +} diff --git a/patches/openvm-sdk/src/prover/evm.rs b/patches/openvm-sdk/src/prover/evm.rs new file mode 100644 index 00000000..1c84e4e2 --- /dev/null +++ b/patches/openvm-sdk/src/prover/evm.rs @@ -0,0 +1,127 @@ +use std::sync::Arc; + +use eyre::Result; +use openvm_circuit::arch::{ + instructions::exe::VmExe, Executor, MeteredExecutor, PreflightExecutor, VmBuilder, + VmExecutionConfig, +}; +use openvm_continuations::RootSC; +use openvm_stark_backend::{p3_field::PrimeField32, proof::Proof, StarkEngine, Val}; +use openvm_verify_stark_host::VmStarkProof; + +#[cfg(feature = "evm-prove")] +use crate::prover::Halo2Prover; +use crate::{ + prover::{ + vm::types::VmProvingKey, AggProver, DeferralPathProver, InternalLayerMetadata, RootProver, + StarkProver, + }, + DeferralInput, StdIn, SC, +}; + +/// EVM prover that produces a root STARK proof with Halo2 wrapping. +/// +/// [`EvmProver::prove_root`] outputs the unwrapped root STARK, while +/// [`EvmProver::prove_root_from_vm_stark_proof`] outputs the unwrapped root STARK from an +/// intermediate STARK proof, for more finegrained separation of work +/// [`EvmProver::prove_evm`] produces an [`EvmProof`](crate::types::EvmProof) +/// suitable for on-chain verification. +pub struct EvmProver +where + E: StarkEngine, + VB: VmBuilder, +{ + pub stark_prover: StarkProver, + pub root_prover: Arc, + #[cfg(feature = "evm-prove")] + pub halo2_prover: Option, +} + +impl EvmProver +where + E: StarkEngine, + VB: VmBuilder + Clone, + Val: PrimeField32, +{ + pub fn new( + vm_builder: VB, + app_vm_pk: &VmProvingKey, + app_exe: Arc>>, + agg_prover: Arc, + def_prover: Option>, + root_prover: Arc, + #[cfg(feature = "evm-prove")] halo2_prover: Option, + ) -> Result { + Ok(Self { + stark_prover: StarkProver::new(vm_builder, app_vm_pk, app_exe, agg_prover, def_prover)?, + root_prover, + #[cfg(feature = "evm-prove")] + halo2_prover, + }) + } + + pub fn prove_root_from_vm_stark_proof( + &mut self, + stark_proof: VmStarkProof, + metadata: &mut InternalLayerMetadata, + ) -> Result> + where + >>::Executor: Executor> + + MeteredExecutor> + + PreflightExecutor, VB::RecordArena>, + { + #[cfg(test)] + { + let agg_vk = self + .stark_prover + .agg_prover + .internal_recursive_prover + .get_vk() + .as_ref() + .clone(); + let baseline = self.stark_prover.generate_baseline(); + crate::GenericSdk::::verify_proof(agg_vk, baseline, &stark_proof)?; + } + + const MAX_ROOT_TRACEGEN_RETRIES: usize = 8; + let agg_prover = &self.stark_prover.agg_prover; + self.root_prover + .prove(stark_proof, MAX_ROOT_TRACEGEN_RETRIES, |p| { + agg_prover.wrap_proof(p, metadata) + }) + } + + pub fn prove_root( + &mut self, + input: StdIn>, + def_inputs: &[DeferralInput], + ) -> Result> + where + >>::Executor: Executor> + + MeteredExecutor> + + PreflightExecutor, VB::RecordArena>, + { + let (stark_proof, mut internal_metadata) = self.stark_prover.prove(input, def_inputs)?; + self.prove_root_from_vm_stark_proof(stark_proof, &mut internal_metadata) + } + + #[cfg(feature = "evm-prove")] + pub fn prove_evm( + &mut self, + input: StdIn>, + def_inputs: &[DeferralInput], + ) -> Result + where + >>::Executor: Executor> + + MeteredExecutor> + + PreflightExecutor, VB::RecordArena>, + { + let root_proof = self.prove_root(input, def_inputs)?; + let evm_proof = self + .halo2_prover + .as_ref() + .unwrap() + .prove_for_evm(&root_proof); + Ok(evm_proof) + } +} diff --git a/patches/openvm-sdk/src/prover/halo2.rs b/patches/openvm-sdk/src/prover/halo2.rs new file mode 100644 index 00000000..145d3b14 --- /dev/null +++ b/patches/openvm-sdk/src/prover/halo2.rs @@ -0,0 +1,56 @@ +use std::sync::Arc; + +use openvm_continuations::RootSC; +use openvm_stark_backend::proof::Proof; +use openvm_static_verifier::{Halo2Params, Halo2ParamsReader}; +use tracing::{info, info_span}; + +use crate::{keygen::Halo2ProvingKey, types::EvmProof}; + +#[derive(Clone)] +pub struct Halo2Prover { + halo2_pk: Halo2ProvingKey, + verifier_srs: Arc, + wrapper_srs: Arc, +} + +impl Halo2Prover { + pub fn new(reader: &impl Halo2ParamsReader, halo2_pk: Halo2ProvingKey) -> Self { + let verifier_k = halo2_pk.verifier.pinning.metadata.config_params.k; + let wrapper_k = halo2_pk.wrapper.pinning.metadata.config_params.k; + info!(verifier_k, wrapper_k, "Halo2Prover initialized"); + let verifier_srs = reader.read_params(verifier_k); + let wrapper_srs = reader.read_params(wrapper_k); + Self { + halo2_pk, + verifier_srs, + wrapper_srs, + } + } + + pub fn prove_for_evm(&self, root_proof: &Proof) -> EvmProof { + #[cfg(feature = "metrics")] + { + let verifier_k = self.halo2_pk.verifier.pinning.metadata.config_params.k; + let wrapper_k = self.halo2_pk.wrapper.pinning.metadata.config_params.k; + metrics::gauge!("halo2_verifier_k", "group" => "halo2_outer").set(verifier_k as f64); + metrics::gauge!("halo2_wrapper_k", "group" => "halo2_wrapper").set(wrapper_k as f64); + } + let snark = info_span!("total_proof", group = "halo2_outer").in_scope(|| { + self.halo2_pk + .verifier + .prove_wrapped(&self.verifier_srs, root_proof) + }); + info_span!("total_proof", group = "halo2_wrapper").in_scope(|| { + let raw = self + .halo2_pk + .wrapper + .prove_for_evm(&self.wrapper_srs, snark); + EvmProof::from(raw) + }) + } + + pub fn pk(&self) -> Halo2ProvingKey { + self.halo2_pk.clone() + } +} diff --git a/patches/openvm-sdk/src/prover/mod.rs b/patches/openvm-sdk/src/prover/mod.rs new file mode 100644 index 00000000..3f3129b1 --- /dev/null +++ b/patches/openvm-sdk/src/prover/mod.rs @@ -0,0 +1,22 @@ +mod agg; +mod app; +mod deferral; +#[cfg(feature = "root-prover")] +mod evm; +#[cfg(feature = "evm-prove")] +mod halo2; +#[cfg(feature = "root-prover")] +mod root; +mod stark; +pub mod vm; + +pub use agg::*; +pub use app::*; +pub use deferral::*; +#[cfg(feature = "root-prover")] +pub use evm::*; +#[cfg(feature = "evm-prove")] +pub use halo2::*; +#[cfg(feature = "root-prover")] +pub use root::*; +pub use stark::*; diff --git a/patches/openvm-sdk/src/prover/root.rs b/patches/openvm-sdk/src/prover/root.rs new file mode 100644 index 00000000..cc35c0c4 --- /dev/null +++ b/patches/openvm-sdk/src/prover/root.rs @@ -0,0 +1,238 @@ +use std::sync::Arc; + +use eyre::Result; +use openvm_circuit::{ + arch::{ + instructions::{ + exe::VmExe, instruction::Instruction, program::Program, LocalOpcode, SystemOpcode, + }, + SystemConfig, + }, + system::memory::dimensions::MemoryDimensions, +}; +use openvm_continuations::{prover::engine_device_ctx, CommitBytes, RootSC, SC}; +use openvm_sdk_config::SdkVmBuilder; +use openvm_stark_backend::{ + keygen::types::{MultiStarkProvingKey, MultiStarkVerifyingKey}, + proof::Proof, + prover::ProvingContext, + StarkEngine, SystemParams, +}; +use openvm_stark_sdk::config::{ + app_params_with_100_bits_security, + baby_bear_poseidon2::{Digest, F}, + MAX_APP_LOG_STACKED_HEIGHT, +}; +use openvm_verify_stark_host::VmStarkProof; +use tracing::info_span; + +use crate::{ + config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}, + keygen::AppProvingKey, + prover::{AggProver, DeferralPathProver, StarkProver}, + StdIn, +}; + +// CPU engine used for `compute_root_proof_heights` — trace heights are structural +// and backend-independent, so we always use the faster CPU engine for that step. +type CpuRootE = + openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_continuations::prover::RootGpuProver as RootInnerProver; + type E = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine; + type ChildE = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; + } else { + use openvm_continuations::prover::RootCpuProver as RootInnerProver; + type E = openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; + type ChildE = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; + } +} + +pub struct RootProver(pub RootInnerProver); + +impl RootProver { + pub fn new( + internal_recursive_vk: Arc>, + internal_recursive_vk_commit: CommitBytes, + system_params: SystemParams, + memory_dimensions: MemoryDimensions, + num_user_pvs: usize, + def_hook_commit: Option, + trace_heights: Option>, + ) -> Self { + let inner = RootInnerProver::new::( + internal_recursive_vk, + internal_recursive_vk_commit, + system_params, + memory_dimensions, + num_user_pvs, + def_hook_commit.map(Into::into), + trace_heights, + ); + Self(inner) + } + + pub fn from_pk( + internal_recursive_vk: Arc>, + internal_recursive_vk_commit: CommitBytes, + pk: Arc>, + memory_dimensions: MemoryDimensions, + num_user_pvs: usize, + def_hook_commit: Option, + trace_heights: Option>, + ) -> Self { + let inner = RootInnerProver::from_pk::( + internal_recursive_vk, + internal_recursive_vk_commit, + pk, + memory_dimensions, + num_user_pvs, + def_hook_commit.map(Into::into), + trace_heights, + ); + Self(inner) + } + + pub fn generate_proving_ctx( + &self, + input: VmStarkProof, + ) -> Option::PB>> { + let engine = E::new(self.0.get_pk().params.clone()); + let ctx = info_span!("tracegen_attempt", group = format!("root")).in_scope(|| { + self.0.generate_proving_ctx( + input.inner, + &input.user_pvs_proof, + input.deferral_merkle_proofs.as_ref(), + engine_device_ctx(&engine), + ) + }); + ctx + } + + pub fn prove_from_ctx( + &self, + ctx: ProvingContext<::PB>, + ) -> Result> { + let proof = info_span!("agg_layer", group = format!("root")) + .in_scope(|| info_span!("root").in_scope(|| self.0.root_prove_from_ctx::(ctx)))?; + Ok(proof) + } + + pub fn prove( + &self, + mut stark_proof: VmStarkProof, + max_retries: usize, + mut wrap: impl FnMut(VmStarkProof) -> Result, + ) -> Result> { + let mut attempt = 0usize; + let ctx = loop { + if let Some(ctx) = self.generate_proving_ctx(stark_proof.clone()) { + break ctx; + } + if attempt >= max_retries { + return Err(eyre::eyre!( + "root tracegen returned None after {max_retries} retries" + )); + } + stark_proof = wrap(stark_proof)?; + attempt += 1; + }; + + // Internal sanity (SDK tests only): a successful tracegen must land at + // exactly the root verifier's fixed, expected trace heights. + #[cfg(test)] + for ((air_idx, air_ctx), expected_height) in ctx + .per_trace + .iter() + .zip(self.0.get_trace_heights().unwrap()) + { + assert_eq!( + air_ctx.height(), + expected_height, + "height mismatch at {air_idx}" + ); + } + + self.prove_from_ctx(ctx) + } +} + +pub fn compute_root_proof_heights( + system_config: SystemConfig, + agg_params: AggregationSystemParams, + agg_tree_config: AggregationTreeConfig, + root_params: SystemParams, + def_prover: Option>, +) -> Result> { + let dummy_program = Program::::from_instructions(&[Instruction::from_isize( + SystemOpcode::TERMINATE.global_opcode(), + 0, + 0, + 0, + 0, + 0, + )]); + let dummy_exe = Arc::new(VmExe::new(dummy_program)); + + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + + let mut app_config = AppConfig::riscv64(app_params_with_100_bits_security( + MAX_APP_LOG_STACKED_HEIGHT, + )); + app_config.app_vm_config.system.config = system_config; + + let def_hook_cached_commit = def_prover.as_ref().map(|p| p.def_hook_cached_commit()); + let def_hook_commit = def_prover.as_ref().map(|p| p.def_hook_commit().into()); + + let app_pk = AppProvingKey::keygen(app_config)?; + + let agg_prover = Arc::new(AggProver::new( + Arc::new(app_pk.app_vm_pk.vm_pk.get_vk()), + AggregationConfig { params: agg_params }, + agg_tree_config, + def_hook_cached_commit, + )); + + let mut stark_prover = StarkProver::::new( + Default::default(), + &app_pk.app_vm_pk, + dummy_exe, + agg_prover.clone(), + def_prover, + )?; + let (agg_proof, _) = stark_prover.prove(StdIn::default(), &[])?; + + // Use the CPU engine for root keygen + tracegen: trace heights are structural + // and backend-independent, so we avoid expensive GPU BN254 keygen here. + let root_prover = openvm_continuations::prover::RootCpuProver::new::( + agg_prover.internal_recursive_prover.get_vk(), + agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap() + .commitment + .into(), + root_params, + memory_dimensions, + num_user_pvs, + def_hook_commit, + None, + ); + let root_proving_ctx: ProvingContext<::PB> = root_prover + .generate_proving_ctx( + agg_proof.inner, + &agg_proof.user_pvs_proof, + agg_proof.deferral_merkle_proofs.as_ref(), + &(), + ) + .unwrap(); + + let ret = root_proving_ctx + .into_iter() + .map(|(_, air_ctx)| air_ctx.height()) + .collect(); + Ok(ret) +} diff --git a/patches/openvm-sdk/src/prover/stark.rs b/patches/openvm-sdk/src/prover/stark.rs new file mode 100644 index 00000000..407f6e01 --- /dev/null +++ b/patches/openvm-sdk/src/prover/stark.rs @@ -0,0 +1,196 @@ +use std::{borrow::Borrow, sync::Arc}; + +use eyre::Result; +use openvm_circuit::{ + arch::{ + hasher::poseidon2::vm_poseidon2_hasher, instructions::exe::VmExe, Executor, + MeteredExecutor, PreflightExecutor, VmBuilder, VmExecutionConfig, + }, + system::memory::merkle::MerkleTree, +}; +use openvm_stark_backend::{p3_field::PrimeField32, StarkEngine, Val}; +use openvm_stark_sdk::config::baby_bear_poseidon2::{Digest, F}; +use openvm_verify_stark_host::{ + pvs::{DeferralPvs, DEF_PVS_AIR_ID}, + vk::VerificationBaseline, + VmStarkProof, +}; + +use crate::{ + prover::{ + deferral::compute_deferral_merkle_proofs, vm::types::VmProvingKey, AggProver, AppProver, + DeferralProver, InternalLayerMetadata, + }, + DeferralInput, StdIn, SC, +}; + +pub struct StarkProver +where + E: StarkEngine, + VB: VmBuilder, +{ + pub app_prover: AppProver, + pub agg_prover: Arc, + pub def_prover: Option>, +} + +#[derive(derive_new::new)] +pub struct DeferralPathProver { + pub deferral_prover: Arc, + pub agg_prover: Arc, +} + +impl StarkProver +where + E: StarkEngine, + VB: VmBuilder, + Val: PrimeField32, +{ + pub fn new( + vm_builder: VB, + app_vm_pk: &VmProvingKey, + app_exe: Arc>>, + agg_prover: Arc, + def_prover: Option>, + ) -> Result { + Ok(Self { + app_prover: AppProver::new(vm_builder, app_vm_pk, app_exe)?, + agg_prover, + def_prover, + }) + } + + pub fn set_program_name(&mut self, program_name: impl AsRef) -> &mut Self { + self.app_prover.set_program_name(program_name); + self + } + + pub fn with_program_name(mut self, program_name: impl AsRef) -> Self { + self.set_program_name(program_name); + self + } + + pub fn prove( + &mut self, + vm_input: StdIn>, + def_inputs: &[DeferralInput], + ) -> Result<(VmStarkProof, InternalLayerMetadata)> + where + >>::Executor: Executor> + + MeteredExecutor> + + PreflightExecutor, VB::RecordArena>, + { + let has_deferrals = self.def_prover.is_some(); + let memory_dimensions = self.app_prover.memory_dimensions(); + + // Build the initial memory merkle tree before proving (needed for deferral proofs). + let initial_merkle_tree = if has_deferrals { + let hasher = vm_poseidon2_hasher(); + let initial_memory = &self + .app_prover + .instance() + .state() + .as_ref() + .expect("initial state should exist before proving") + .memory + .memory; + Some(MerkleTree::from_memory( + initial_memory, + &memory_dimensions, + &hasher, + )) + } else { + None + }; + + let continuation_proof = self.app_prover.prove(vm_input)?; + let (mut stark_proof, mut internal_metadata) = + self.agg_prover.prove_vm(continuation_proof)?; + + if !def_inputs.is_empty() { + let def_prover = self.def_prover.as_ref().unwrap(); + let def_hook_proofs = def_prover.deferral_prover.prove(def_inputs)?; + let (def_proof, def_internal_recursive_layer) = + def_prover.agg_prover.prove_def(def_hook_proofs)?; + stark_proof = self.agg_prover.prove_mixed( + stark_proof, + def_proof, + &mut internal_metadata, + def_internal_recursive_layer, + )?; + } + + // We add one additional internal_recursive layer to reduce the proof size. + const ADDITIONAL_INTERNAL_RECURSIVE_LAYERS: usize = 1; + for _ in 0..ADDITIONAL_INTERNAL_RECURSIVE_LAYERS { + stark_proof = self + .agg_prover + .wrap_proof(stark_proof, &mut internal_metadata)?; + } + + // Generate deferral merkle proofs if deferrals are enabled. + if has_deferrals { + let hasher = vm_poseidon2_hasher(); + let final_memory = &self + .app_prover + .instance() + .state() + .as_ref() + .expect("final state should exist after proving") + .memory + .memory; + let final_merkle_tree = + MerkleTree::from_memory(final_memory, &memory_dimensions, &hasher); + + let def_pvs: &DeferralPvs = stark_proof.inner.public_values[DEF_PVS_AIR_ID] + .as_slice() + .borrow(); + let depth = def_pvs.depth.as_canonical_u32() as usize; + + stark_proof.deferral_merkle_proofs = Some(compute_deferral_merkle_proofs( + memory_dimensions, + initial_merkle_tree.as_ref().unwrap(), + &final_merkle_tree, + depth, + )); + } + + Ok((stark_proof, internal_metadata)) + } + + pub fn generate_baseline(&self) -> VerificationBaseline { + VerificationBaseline { + app_exe_commit: self.app_prover.app_exe_commit(), + memory_dimensions: self.app_prover.memory_dimensions(), + num_user_pvs: self.app_prover.num_user_pvs(), + app_vk_commit: self.agg_prover.leaf_prover.get_vk_commit(false), + leaf_vk_commit: self + .agg_prover + .internal_for_leaf_prover + .get_vk_commit(false), + internal_for_leaf_vk_commit: self + .agg_prover + .internal_recursive_prover + .get_vk_commit(false), + internal_recursive_vk_commit: self + .agg_prover + .internal_recursive_prover + .get_vk_commit(true), + expected_def_hook_commit: self.def_prover.as_ref().map(|dp| dp.def_hook_commit()), + } + } + + pub fn app_vm_commit(&self) -> Digest { + self.agg_prover.vm_or_hook_commit() + } +} + +impl DeferralPathProver { + pub fn def_hook_cached_commit(&self) -> Digest { + self.deferral_prover.def_hook_prover.get_cached_commit() + } + + pub fn def_hook_commit(&self) -> Digest { + self.agg_prover.vm_or_hook_commit() + } +} diff --git a/patches/openvm-sdk/src/prover/vm/mod.rs b/patches/openvm-sdk/src/prover/vm/mod.rs new file mode 100644 index 00000000..5b77b581 --- /dev/null +++ b/patches/openvm-sdk/src/prover/vm/mod.rs @@ -0,0 +1,27 @@ +use std::sync::Arc; + +use openvm_circuit::arch::{ + instructions::exe::VmExe, VirtualMachine, VirtualMachineError, VmBuilder, VmInstance, +}; +use openvm_stark_backend::{prover::DeviceDataTransporter, StarkEngine, Val}; + +use crate::prover::vm::types::VmProvingKey; + +pub mod types; + +pub fn new_local_prover( + vm_builder: VB, + vm_pk: &VmProvingKey, + exe: Arc>>, +) -> Result, VirtualMachineError> +where + E: StarkEngine, + VB: VmBuilder, +{ + let engine = E::new(vm_pk.get_params()); + let d_pk = engine.device().transport_pk_to_device(&*vm_pk.vm_pk); + let vm = VirtualMachine::new(engine, vm_builder, vm_pk.vm_config.clone(), d_pk)?; + let cached_program_trace = vm.commit_program_on_device(&exe.program); + let instance = VmInstance::new(vm, exe, cached_program_trace)?; + Ok(instance) +} diff --git a/patches/openvm-sdk/src/prover/vm/types.rs b/patches/openvm-sdk/src/prover/vm/types.rs new file mode 100644 index 00000000..f3de4462 --- /dev/null +++ b/patches/openvm-sdk/src/prover/vm/types.rs @@ -0,0 +1,18 @@ +use std::sync::Arc; + +use derivative::Derivative; +use openvm_stark_backend::{keygen::types::MultiStarkProvingKey, SystemParams}; +use serde::{Deserialize, Serialize}; + +/// Proving key for a specific VM. +#[derive(Serialize, Deserialize, Derivative)] +pub struct VmProvingKey { + pub vm_config: VC, + pub vm_pk: Arc>, +} + +impl VmProvingKey { + pub fn get_params(&self) -> SystemParams { + self.vm_pk.params.clone() + } +} diff --git a/patches/openvm-sdk/src/solidity.rs b/patches/openvm-sdk/src/solidity.rs new file mode 100644 index 00000000..64f5e5fb --- /dev/null +++ b/patches/openvm-sdk/src/solidity.rs @@ -0,0 +1,283 @@ +use std::{ + fs::{create_dir_all, write}, + io::Write, + path::Path, + process::{Command, Stdio}, +}; + +use eyre::Context; +use serde_json::{json, Value}; +use tempfile::tempdir; + +use crate::{ + error::SdkError, + fs::{ + EVM_HALO2_VERIFIER_BASE_NAME, EVM_HALO2_VERIFIER_INTERFACE_NAME, + EVM_HALO2_VERIFIER_PARENT_NAME, + }, + types::{EvmHalo2Verifier, EvmVerifierByteCode}, + OPENVM_VERSION, +}; + +const EVM_HALO2_VERIFIER_TEMPLATE: &str = + include_str!("../contracts/template/OpenVmHalo2Verifier.sol"); +const EVM_HALO2_VERIFIER_INTERFACE: &str = + include_str!("../contracts/src/IOpenVmHalo2Verifier.sol"); + +alloy_sol_types::sol! { + #[allow(missing_docs)] + interface IOpenVmHalo2Verifier { + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view; + } +} + +/// Generate the EVM Halo2 verifier Solidity contract, compile it with solc, and return +/// the verifier artifact. +pub(crate) fn generate_halo2_verifier_solidity( + halo2_pk: &crate::keygen::Halo2ProvingKey, + halo2_params_reader: &crate::halo2_params::CacheHalo2ParamsReader, +) -> Result { + let wrapper_k = halo2_pk.wrapper.pinning.metadata.config_params.k; + let params = halo2_params_reader.read_params(wrapper_k); + + // Generate the base Halo2Verifier Solidity code from snark-verifier + // (via the wrapper circuit, which is what produces the final EVM proof) + let fallback_verifier = halo2_pk.wrapper.generate_fallback_evm_verifier(¶ms); + let halo2_verifier_code = fallback_verifier.sol_code; + + // Compute public values length from the wrapper circuit's instances. + // The wrapper's instances layout is: + // [0..12]: KZG accumulator + // [12]: app_exe_commit + // [13]: app vm commit + // [14..]: user public values + let num_pvs = halo2_pk + .wrapper + .pinning + .metadata + .num_pvs + .first() + .expect("Expected at least one instance column"); + // Subtract 12 (accumulator) + 2 (commits) = 14 to get the number of user + // public value limbs exposed by the static verifier circuit. + let pvs_length = num_pvs + .checked_sub(crate::types::NUM_BN254_ACCUMULATOR + 2) + .expect("Unexpected number of wrapper circuit public values"); + // In rv64 each public value limb occupies U16_CELL_SIZE bytes, while in + // rv32 it occupies one byte. The Solidity contract needs both the number of + // public-value limbs (Fr instances) and the limb byte width. + let pvs_limb_size = openvm_circuit::arch::U16_CELL_SIZE; + let pvs_byte_length = pvs_length * pvs_limb_size; + + assert!( + pvs_byte_length <= 8192, + "OpenVM Halo2 verifier contract does not support more than 8192 public value bytes" + ); + + // PROOF_DATA_LENGTH is now a constant in the template: (12 + 43) * 32 + // Fill out template placeholders + let openvm_verifier_code = EVM_HALO2_VERIFIER_TEMPLATE + .replace("{PUBLIC_VALUES_LENGTH}", &pvs_length.to_string()) + .replace("{PUBLIC_VALUES_LIMB_SIZE}", &pvs_limb_size.to_string()) + .replace("{OPENVM_VERSION}", OPENVM_VERSION); + + // Format Solidity code if forge-fmt is available (requires Rust 1.91+) + let (formatted_interface, formatted_halo2_verifier_code, formatted_openvm_verifier_code) = + format_solidity_sources( + EVM_HALO2_VERIFIER_INTERFACE, + &halo2_verifier_code, + &openvm_verifier_code, + ); + + // Create temp dir + let temp_dir = tempdir() + .wrap_err("Failed to create temp dir") + .map_err(SdkError::Other)?; + let temp_path = temp_dir.path(); + let root_path = Path::new("src").join(format!("v{OPENVM_VERSION}")); + + // Make interfaces dir + let interfaces_path = root_path.join("interfaces"); + + // This will also create the dir for root_path, so no need to explicitly + // create it + create_dir_all(temp_path.join(&interfaces_path))?; + + let interface_file_path = interfaces_path.join(EVM_HALO2_VERIFIER_INTERFACE_NAME); + let parent_file_path = root_path.join(EVM_HALO2_VERIFIER_PARENT_NAME); + let base_file_path = root_path.join(EVM_HALO2_VERIFIER_BASE_NAME); + + // Write the files to the temp dir. This is only for compilation + // purposes. + write(temp_path.join(&interface_file_path), &formatted_interface)?; + write( + temp_path.join(&parent_file_path), + &formatted_halo2_verifier_code, + )?; + write( + temp_path.join(&base_file_path), + &formatted_openvm_verifier_code, + )?; + + // Run solc from the temp dir + let solc_input = json!({ + "language": "Solidity", + "sources": { + interface_file_path.to_str().unwrap(): { + "content": formatted_interface + }, + parent_file_path.to_str().unwrap(): { + "content": formatted_halo2_verifier_code + }, + base_file_path.to_str().unwrap(): { + "content": formatted_openvm_verifier_code + } + }, + "settings": { + "remappings": ["forge-std/=lib/forge-std/src/"], + "optimizer": { + "enabled": true, + "runs": 100000, + "details": { + "constantOptimizer": false, + "yul": false + } + }, + "evmVersion": "paris", + "viaIR": false, + "outputSelection": { + "*": { + "*": ["metadata", "evm.bytecode.object"] + } + } + } + }); + + let mut child = Command::new("solc") + .current_dir(temp_path) + .arg("--standard-json") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("Failed to spawn solc"); + + child + .stdin + .as_mut() + .expect("Failed to open stdin") + .write_all(solc_input.to_string().as_bytes()) + .expect("Failed to write to stdin"); + + let output = child.wait_with_output().expect("Failed to read output"); + + if !output.status.success() { + return Err(SdkError::Other(eyre::eyre!( + "solc exited with status {}: {}", + output.status, + String::from_utf8_lossy(&output.stderr) + ))); + } + + let parsed: Value = + serde_json::from_slice(&output.stdout).map_err(|e| SdkError::Other(e.into()))?; + + let bytecode = parsed + .get("contracts") + .expect("No 'contracts' field found") + .get(format!("src/v{OPENVM_VERSION}/OpenVmHalo2Verifier.sol")) + .unwrap_or_else(|| panic!("No 'src/v{OPENVM_VERSION}/OpenVmHalo2Verifier.sol' field found")) + .get("OpenVmHalo2Verifier") + .expect("No 'OpenVmHalo2Verifier' field found") + .get("evm") + .expect("No 'evm' field found") + .get("bytecode") + .expect("No 'bytecode' field found") + .get("object") + .expect("No 'object' field found") + .as_str() + .expect("No 'object' field found"); + + let bytecode = hex::decode(bytecode).expect("Invalid hex in Binary"); + + let evm_verifier = EvmHalo2Verifier { + halo2_verifier_code: formatted_halo2_verifier_code, + openvm_verifier_code: formatted_openvm_verifier_code, + openvm_verifier_interface: formatted_interface, + artifact: EvmVerifierByteCode { + sol_compiler_version: "0.8.19".to_string(), + sol_compiler_options: solc_input.get("settings").unwrap().to_string(), + bytecode, + }, + }; + Ok(evm_verifier) +} + +/// Verify an EVM Halo2 proof by deploying the verifier bytecode in a local EVM. +pub(crate) fn verify_evm_halo2_proof( + openvm_verifier: &EvmHalo2Verifier, + evm_proof: crate::types::EvmProof, +) -> Result { + // Convert EvmProof → RawEvmProof for the static verifier's evm_verify + let raw_evm_proof: openvm_static_verifier::keygen::RawEvmProof = evm_proof.into(); + let deployment_code = &openvm_verifier.artifact.bytecode; + + let gas_cost = openvm_static_verifier::keygen::evm_verify(deployment_code, &raw_evm_proof) + .map_err(|reason| { + SdkError::Other(eyre::eyre!("EVM proof verification failed: {reason}")) + })?; + + Ok(gas_cost) +} + +/// Format Solidity sources using forge-fmt when available, or return them as-is. +fn format_solidity_sources( + interface: &str, + halo2_verifier: &str, + openvm_verifier: &str, +) -> (String, String, String) { + #[cfg(feature = "evm-verify-fmt")] + { + use forge_fmt::{ + format, FormatterConfig, IntTypes, MultilineFuncHeaderStyle, NumberUnderscore, + QuoteStyle, SingleLineBlockStyle, + }; + + let config = FormatterConfig { + line_length: 120, + tab_width: 4, + bracket_spacing: true, + int_types: IntTypes::Long, + multiline_func_header: MultilineFuncHeaderStyle::AttributesFirst, + quote_style: QuoteStyle::Double, + number_underscore: NumberUnderscore::Thousands, + single_line_statement_blocks: SingleLineBlockStyle::Preserve, + override_spacing: false, + wrap_comments: false, + ignore: vec![], + contract_new_lines: false, + sort_imports: false, + ..Default::default() + }; + + let formatted_interface = format(interface, config.clone()) + .into_result() + .expect("Failed to format interface"); + let formatted_halo2 = format(halo2_verifier, config.clone()) + .into_result() + .expect("Failed to format halo2 verifier code"); + let formatted_openvm = format(openvm_verifier, config) + .into_result() + .expect("Failed to format openvm verifier code"); + + (formatted_interface, formatted_halo2, formatted_openvm) + } + #[cfg(not(feature = "evm-verify-fmt"))] + { + ( + interface.to_string(), + halo2_verifier.to_string(), + openvm_verifier.to_string(), + ) + } +} diff --git a/patches/openvm-sdk/src/stdin.rs b/patches/openvm-sdk/src/stdin.rs new file mode 100644 index 00000000..409e053a --- /dev/null +++ b/patches/openvm-sdk/src/stdin.rs @@ -0,0 +1,86 @@ +use std::collections::VecDeque; + +use itertools::Itertools; +use openvm_circuit::arch::{deferral::DeferralState, Streams}; +use openvm_stark_backend::{ + codec::{Decode, Encode}, + p3_field::Field, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Serialize, Deserialize)] +pub struct StdIn { + pub buffer: VecDeque>, + pub deferrals: Vec, +} + +impl StdIn { + pub fn from_bytes(data: &[u8]) -> Self { + let mut ret = Self::default(); + ret.write_bytes(data); + ret + } + + pub fn read(&mut self) -> Option> { + self.buffer.pop_front() + } + + pub fn write(&mut self, data: &T) { + let words = openvm::serde::to_vec(data).unwrap(); + let bytes: Vec = words.into_iter().flat_map(|w| w.to_le_bytes()).collect(); + self.write_bytes(&bytes); + } + + pub fn write_bytes(&mut self, data: &[u8]) { + let field_data = data.iter().map(|b| F::from_u8(*b)).collect(); + self.buffer.push_back(field_data); + } + + pub fn write_field(&mut self, data: &[F]) { + self.buffer.push_back(data.to_vec()); + } +} + +impl From> for Streams { + fn from(mut std_in: StdIn) -> Self { + let mut data = Vec::>::new(); + while let Some(input) = std_in.read() { + data.push(input); + } + let mut ret = Streams::new(data); + ret.deferrals = std_in.deferrals; + ret + } +} + +impl From>> for StdIn { + fn from(inputs: Vec>) -> Self { + let mut ret = StdIn::::default(); + for input in inputs { + ret.write_field(&input); + } + ret + } +} + +#[derive(Clone, Default, Serialize, Deserialize)] +pub struct DeferralInput { + pub byte_vec: Vec>, +} + +impl DeferralInput { + pub fn into_inputs(self) -> Vec { + self.byte_vec + .iter() + .map(|input| I::decode_from_bytes(input).unwrap()) + .collect_vec() + } + + pub fn from_inputs(inputs: &[I]) -> Self { + let byte_vec = inputs + .iter() + .map(|input| input.encode_to_vec().unwrap()) + .collect_vec(); + Self { byte_vec } + } +} diff --git a/patches/openvm-sdk/src/tests.rs b/patches/openvm-sdk/src/tests.rs new file mode 100644 index 00000000..69067400 --- /dev/null +++ b/patches/openvm-sdk/src/tests.rs @@ -0,0 +1,843 @@ +use std::{slice::from_ref, sync::Arc}; + +use eyre::Result; +use openvm::platform::memory::MEM_SIZE; +use openvm_circuit::arch::{instructions::DEFERRAL_AS, U16_CELL_SIZE}; +use openvm_continuations::prover::DeferralCircuitProver; +use openvm_deferral_circuit::DeferralFn; +use openvm_stark_backend::{codec::Encode, StarkEngine, SystemParams}; +use openvm_stark_sdk::{ + config::{ + app_params_with_100_bits_security, hook_params_with_100_bits_security, + internal_params_with_100_bits_security, + }, + utils::setup_tracing, +}; +use openvm_transpiler::elf::Elf; +use openvm_verify_stark_circuit::extension::{ + get_deferral_state, get_raw_deferral_results, verify_stark_deferral_fn, +}; +use openvm_verify_stark_host::{ + vk::{VerificationBaseline, VmStarkVerifyingKey}, + VmStarkProof, +}; + +use crate::{ + config::{AggregationConfig, AggregationSystemParams, AppConfig, DEFAULT_APP_L_SKIP}, + prover::{DeferralPathProver, DeferralProof, DeferralProver}, + DeferralInput, Sdk, StdIn, +}; + +cfg_if::cfg_if! { + if #[cfg(feature = "cuda")] { + use openvm_verify_stark_circuit::prover::DeferredVerifyGpuProver as VerifyProver; + use openvm_verify_stark_circuit::prover::DeferredVerifyGpuCircuitProver as VerifyCircuitProver; + type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; + type RootE = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine; + } else { + use openvm_verify_stark_circuit::prover::DeferredVerifyCpuProver as VerifyProver; + use openvm_verify_stark_circuit::prover::DeferredVerifyCpuCircuitProver as VerifyCircuitProver; + type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; + type RootE = openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; + } +} + +/// Creates a fibonacci SDK with standard test parameters. +fn make_fib_sdk() -> (Sdk, SystemParams, AggregationSystemParams) { + let n_stack = 19; + let app_params = app_params_with_100_bits_security(DEFAULT_APP_L_SKIP + n_stack); + let agg_params = AggregationSystemParams::default(); + let sdk = Sdk::riscv64(app_params.clone(), agg_params.clone()); + (sdk, app_params, agg_params) +} + +/// Generates a fibonacci VM STARK proof using the given SDK. +fn generate_fib_vm_stark_proof(fib_sdk: &Sdk) -> Result<(VmStarkProof, VerificationBaseline)> { + let fib_elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let fib_exe = fib_sdk.convert_to_exe(fib_elf)?; + let n = 100u64; + let mut stdin = StdIn::default(); + stdin.write(&n); + Ok(fib_sdk.prove(fib_exe, stdin, &[])?) +} + +fn make_verify_stark_circuit_prover( + sdk: &Sdk, + def_circuit_params: SystemParams, + def_idx: usize, +) -> VerifyCircuitProver { + let agg_prover = sdk.agg_prover(); + let ir_vk = agg_prover.internal_recursive_prover.get_vk(); + let ir_pcs_data = agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap(); + let system_config = sdk.app_config().app_vm_config.as_ref().clone(); + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + let deferred_verify_prover = VerifyProver::new::( + ir_vk, + ir_pcs_data.commitment.into(), + def_circuit_params, + memory_dimensions, + num_user_pvs, + None, + def_idx, + ); + VerifyCircuitProver::new(deferred_verify_prover) +} + +/// Builds a DeferralProver from a base SDK with `num_deferral_circuits` copies of the +/// verify-stark deferral circuit. +fn make_deferral_prover_with_count( + sdk: &Sdk, + agg_params: &AggregationSystemParams, + num_deferral_circuits: usize, +) -> DeferralProver { + assert!(num_deferral_circuits > 0); + let def_circuit_params = internal_params_with_100_bits_security(); + let verify_stark_prover = make_verify_stark_circuit_prover(sdk, def_circuit_params.clone(), 0); + let hook_params = hook_params_with_100_bits_security(); + let agg_config = AggregationConfig { + params: agg_params.clone(), + }; + let mut deferral_prover = DeferralProver::new(verify_stark_prover, agg_config, hook_params); + for def_idx in 1..num_deferral_circuits { + deferral_prover = deferral_prover.with_prover(make_verify_stark_circuit_prover( + sdk, + def_circuit_params.clone(), + def_idx, + )); + } + deferral_prover +} + +/// Builds a deferral-enabled riscv64 SDK whose App VM inventory includes the +/// deferral periphery chips (DeferralPoseidon2Chip, count chip, etc.). +fn make_deferral_enabled_sdk( + fib_sdk: &Sdk, + app_params: SystemParams, + agg_params: AggregationSystemParams, +) -> Result { + make_deferral_enabled_sdk_with_count(fib_sdk, app_params, agg_params, 1) +} + +fn make_deferral_enabled_sdk_with_count( + fib_sdk: &Sdk, + app_params: SystemParams, + agg_params: AggregationSystemParams, + num_deferral_circuits: usize, +) -> Result { + let deferral_prover = + make_deferral_prover_with_count(fib_sdk, &agg_params, num_deferral_circuits); + let deferral_fns = (0..num_deferral_circuits) + .map(|_| Arc::new(DeferralFn::new(verify_stark_deferral_fn))) + .collect(); + let deferral_ext = deferral_prover.make_extension(deferral_fns); + + let mut vm_config = openvm_sdk_config::SdkVmConfig::riscv64(); + vm_config.deferral = Some(deferral_ext); + vm_config.system.config.memory_config.addr_spaces[DEFERRAL_AS as usize].num_cells = 1 << 25; + + Ok(Sdk::builder() + .app_config(AppConfig::new(vm_config, app_params)) + .agg_params(agg_params) + .deferral_prover(deferral_prover) + .build()?) +} + +fn make_verify_stark_path_sdk( + app_params: SystemParams, + agg_params: AggregationSystemParams, +) -> Result { + let mut vm_config = openvm_sdk_config::SdkVmConfig::riscv64(); + vm_config.system.config.memory_config.addr_spaces[DEFERRAL_AS as usize].num_cells = 1 << 25; + let memory_dimensions = vm_config.system.config.memory_config.memory_dimensions(); + let num_user_pvs = vm_config.system.config.num_public_values; + + let deferral_path_prover = DeferralPathProver::verify_stark( + &agg_params, + hook_params_with_100_bits_security(), + memory_dimensions, + num_user_pvs, + ); + let deferral_ext = deferral_path_prover + .deferral_prover + .make_extension(vec![Arc::new(DeferralFn::new(verify_stark_deferral_fn))]); + vm_config.deferral = Some(deferral_ext); + + Ok(Sdk::builder() + .app_config(AppConfig::new(vm_config, app_params)) + .agg_params(agg_params) + .deferral_path_prover(deferral_path_prover) + .build()?) +} + +fn make_verify_stark_inputs( + child_sdk: &Sdk, + child_proof: &VmStarkProof, + child_baseline: VerificationBaseline, +) -> Result<(StdIn, DeferralInput)> { + let (stdin, mut def_inputs) = + make_verify_stark_inputs_for_indices(child_sdk, child_proof, child_baseline, &[0], 1)?; + Ok((stdin, def_inputs.pop().unwrap())) +} + +fn make_verify_stark_inputs_for_indices( + child_sdk: &Sdk, + child_proof: &VmStarkProof, + child_baseline: VerificationBaseline, + present_def_indices: &[usize], + num_deferral_circuits: usize, +) -> Result<(StdIn, Vec)> { + let child_vk = VmStarkVerifyingKey { + mvk: child_sdk.agg_vk().as_ref().clone(), + baseline: child_baseline, + }; + + let raw_results = get_raw_deferral_results(&child_vk, from_ref(child_proof))?; + assert_eq!(raw_results.len(), 1); + let input_commit: [u8; 32] = raw_results[0].input.clone().try_into().unwrap(); + let output_raw = &raw_results[0].output_raw; + let app_exe_commit: [u8; 32] = output_raw[..32].try_into().unwrap(); + let app_vm_commit: [u8; 32] = output_raw[32..64].try_into().unwrap(); + + let user_public_values = collapse_user_public_values(&output_raw[64..]); + + let mut stdin = StdIn::default(); + stdin.write(&app_exe_commit); + stdin.write(&app_vm_commit); + stdin.write(&user_public_values); + stdin.write(&input_commit); + stdin.deferrals = vec![Default::default(); num_deferral_circuits]; + + let proof_input = DeferralInput::from_inputs(from_ref(child_proof)); + let mut def_inputs = vec![DeferralInput::default(); num_deferral_circuits]; + for &def_idx in present_def_indices { + assert!(def_idx < num_deferral_circuits); + stdin.deferrals[def_idx] = + get_deferral_state(&child_vk, from_ref(child_proof), def_idx as u32)?; + def_inputs[def_idx] = proof_input.clone(); + } + + Ok((stdin, def_inputs)) +} + +fn collapse_user_public_values(expanded: &[u8]) -> Vec { + const F_NUM_BYTES: usize = core::mem::size_of::(); + assert!(expanded.len().is_multiple_of(F_NUM_BYTES)); + let mut user_public_values = Vec::with_capacity(expanded.len() / F_NUM_BYTES * U16_CELL_SIZE); + for bytes in expanded.chunks_exact(F_NUM_BYTES) { + assert_eq!(&bytes[U16_CELL_SIZE..], &[0; F_NUM_BYTES - U16_CELL_SIZE]); + user_public_values.extend_from_slice(&bytes[..U16_CELL_SIZE]); + } + user_public_values +} + +#[test] +fn collapse_user_public_values_preserves_u16_cells() { + let expanded = [0x34, 0x12, 0, 0, 0xcd, 0xab, 0, 0]; + assert_eq!( + collapse_user_public_values(&expanded), + [0x34, 0x12, 0xcd, 0xab] + ); +} + +/// Builds a deferral-enabled verify-stark SDK from a fibonacci SDK and proof. +/// +/// Returns the SDK, the verify-stark stdin, and the deferral input. +fn make_deferral_sdk( + fib_sdk: &Sdk, + fib_proof: VmStarkProof, + fib_baseline: VerificationBaseline, + app_params: SystemParams, + agg_params: AggregationSystemParams, +) -> Result<(Sdk, StdIn, DeferralInput)> { + let (vs_stdin, def_input) = make_verify_stark_inputs(fib_sdk, &fib_proof, fib_baseline)?; + let vs_sdk = make_deferral_enabled_sdk(fib_sdk, app_params, agg_params)?; + + Ok((vs_sdk, vs_stdin, def_input)) +} + +#[test] +fn test_sdk_fibonacci() -> Result<()> { + setup_tracing(); + let (sdk, _app_params, _agg_params) = make_fib_sdk(); + + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let app_exe = sdk.convert_to_exe(elf)?; + + let n = 1000u64; + let mut stdin = StdIn::default(); + stdin.write(&n); + + #[cfg(not(feature = "evm-verify"))] + { + let mut evm_prover = sdk.evm_prover_without_halo2(app_exe)?; + let proof = evm_prover.prove_root(stdin, &[])?; + let vk = evm_prover.root_prover.0.get_vk(); + let engine = RootE::new(vk.inner.params.clone()); + engine.verify(&vk, &proof)?; + } + #[cfg(feature = "evm-verify")] + { + let app_commit = sdk.app_commit(app_exe.clone())?; + let evm_proof = sdk.prove_evm(app_exe, stdin, &[])?; + let openvm_verifier = sdk.generate_halo2_verifier_solidity()?; + let _gas_cost = Sdk::verify_evm_halo2_proof(&openvm_verifier, evm_proof, Some(app_commit))?; + } + + Ok(()) +} + +#[cfg(feature = "rvr")] +#[test] +fn test_sdk_compiled_pure_save_load_roundtrip() -> Result<()> { + let (sdk, _, _) = make_fib_sdk(); + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let exe = sdk.convert_to_exe(elf)?; + + let mut stdin = StdIn::default(); + stdin.write(&100u64); + + let compiled_a = sdk.compile(exe.clone())?; + let baseline = sdk.execute(&compiled_a, stdin.clone())?; + + let tmp = tempfile::tempdir()?; + let lib_path = compiled_a.save(tmp.path())?; + drop(compiled_a); + + let compiled_b = sdk.load_compiled(&lib_path, exe)?; + let reloaded = sdk.execute(&compiled_b, stdin)?; + + assert_eq!(baseline, reloaded); + Ok(()) +} + +#[cfg(feature = "rvr")] +#[test] +fn test_sdk_compiled_metered_save_load_roundtrip() -> Result<()> { + let (sdk, _, _) = make_fib_sdk(); + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let exe = sdk.convert_to_exe(elf)?; + + let mut stdin = StdIn::default(); + stdin.write(&100u64); + + let compiled_a = sdk.compile_metered(exe.clone())?; + let (baseline_pv, baseline_segments) = sdk.execute_metered(&compiled_a, stdin.clone())?; + + let tmp = tempfile::tempdir()?; + let lib_path = compiled_a.save(tmp.path())?; + drop(compiled_a); + + let compiled_b = sdk.load_compiled_metered(&lib_path, exe)?; + let (reloaded_pv, reloaded_segments) = sdk.execute_metered(&compiled_b, stdin)?; + + assert_eq!(baseline_pv, reloaded_pv); + assert_eq!(baseline_segments.len(), reloaded_segments.len()); + for (a, b) in baseline_segments.iter().zip(reloaded_segments.iter()) { + assert_eq!(a.instret_start, b.instret_start); + assert_eq!(a.num_insns, b.num_insns); + assert_eq!(a.trace_heights, b.trace_heights); + } + Ok(()) +} + +#[cfg(feature = "rvr")] +#[test] +fn test_sdk_compiled_metered_cost_save_load_roundtrip() -> Result<()> { + let (sdk, _, _) = make_fib_sdk(); + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let exe = sdk.convert_to_exe(elf)?; + + let mut stdin = StdIn::default(); + stdin.write(&100u64); + + let compiled_a = sdk.compile_metered_cost(exe.clone())?; + let (baseline_pv, baseline_cost) = sdk.execute_metered_cost(&compiled_a, stdin.clone())?; + + let tmp = tempfile::tempdir()?; + let lib_path = compiled_a.save(tmp.path())?; + drop(compiled_a); + + let compiled_b = sdk.load_compiled_metered_cost(&lib_path, exe)?; + let (reloaded_pv, reloaded_cost) = sdk.execute_metered_cost(&compiled_b, stdin)?; + + assert_eq!(baseline_pv, reloaded_pv); + assert_eq!(baseline_cost, reloaded_cost); + Ok(()) +} + +#[test] +fn test_sdk_compiled_metered_execute() -> Result<()> { + let (sdk, _, _) = make_fib_sdk(); + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let exe = sdk.convert_to_exe(elf)?; + + let mut stdin = StdIn::default(); + stdin.write(&100u64); + + let compiled = sdk.compile_metered(exe)?; + let (_, segments) = sdk.execute_metered(&compiled, stdin)?; + assert!(!segments.is_empty()); + Ok(()) +} + +#[test] +fn test_sdk_compiled_metered_cost_execute() -> Result<()> { + let (sdk, _, _) = make_fib_sdk(); + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let exe = sdk.convert_to_exe(elf)?; + + let mut stdin = StdIn::default(); + stdin.write(&100u64); + + let compiled = sdk.compile_metered_cost(exe)?; + let (_, (_, instret)) = sdk.execute_metered_cost(&compiled, stdin)?; + assert!(instret > 0); + Ok(()) +} + +#[test] +fn test_verify_stark_deferral() -> Result<()> { + setup_tracing(); + let (fib_sdk, app_params, agg_params) = make_fib_sdk(); + let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; + let (vs_sdk, vs_stdin, def_input) = + make_deferral_sdk(&fib_sdk, fib_proof, fib_baseline, app_params, agg_params)?; + + let vs_elf = Elf::decode( + include_bytes!("../programs/examples/verify-stark.elf"), + MEM_SIZE as u32, + )?; + let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; + + let mut evm_prover = vs_sdk.evm_prover_without_halo2(vs_exe)?; + let vs_proof = evm_prover.prove_root(vs_stdin, &[def_input])?; + + let vk = evm_prover.root_prover.0.get_vk(); + let engine = RootE::new(vk.inner.params.clone()); + engine.verify(&vk, &vs_proof)?; + + Ok(()) +} + +#[test] +fn test_verify_many_deferrals() -> Result<()> { + setup_tracing(); + const NUM_DEFERRAL_CIRCUITS: usize = 5; + + let (fib_sdk, app_params, agg_params) = make_fib_sdk(); + let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; + let (vs_stdin, def_inputs) = make_verify_stark_inputs_for_indices( + &fib_sdk, + &fib_proof, + fib_baseline, + &[0, 1, 3, 4], + NUM_DEFERRAL_CIRCUITS, + )?; + let vs_sdk = make_deferral_enabled_sdk_with_count( + &fib_sdk, + app_params, + agg_params, + NUM_DEFERRAL_CIRCUITS, + )?; + + let vs_elf = Elf::decode( + include_bytes!("../programs/examples/verify-many.elf"), + MEM_SIZE as u32, + )?; + let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; + + let (vs_proof, vs_baseline) = vs_sdk.prove(vs_exe, vs_stdin, &def_inputs)?; + assert!( + vs_proof.deferral_merkle_proofs.is_some(), + "verify-many proof must carry deferral merkle proofs", + ); + Sdk::verify_proof(vs_sdk.agg_vk().as_ref().clone(), vs_baseline, &vs_proof)?; + + Ok(()) +} + +#[test] +fn test_verify_stark_with_deferral_child() -> Result<()> { + setup_tracing(); + let (fib_sdk, app_params, agg_params) = make_fib_sdk(); + let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; + let (vs_sdk, vs_stdin, def_input) = + make_deferral_sdk(&fib_sdk, fib_proof, fib_baseline, app_params, agg_params)?; + + let vs_elf = Elf::decode( + include_bytes!("../programs/examples/verify-stark.elf"), + MEM_SIZE as u32, + )?; + let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; + + let (vs_proof, _) = vs_sdk.prove(vs_exe, vs_stdin, &[def_input])?; + assert!( + vs_proof.deferral_merkle_proofs.is_some(), + "deferral-enabled verify-stark child proof must carry deferral merkle proofs", + ); + let expected_def_hook_commit = vs_sdk + .def_hook_commit() + .expect("deferral-enabled SDK should expose a deferral hook commit"); + + // ---- Step 5: Feed the encoded proof through the trait adapter ---- + let vs_agg_prover = vs_sdk.agg_prover(); + let vs_ir_vk = vs_agg_prover.internal_recursive_prover.get_vk(); + let vs_ir_pcs_data = vs_agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap(); + let vs_system_config = vs_sdk.app_config().app_vm_config.as_ref().clone(); + + // This nested verifier is intentionally constructed in deferral-aware mode because the + // verify-stark child proof above was itself produced through a deferral-enabled SDK. + let nested_verify_prover = VerifyProver::new::( + vs_ir_vk, + vs_ir_pcs_data.commitment.into(), + internal_params_with_100_bits_security(), + vs_system_config.memory_config.memory_dimensions(), + vs_system_config.num_public_values, + Some(expected_def_hook_commit), + 0, + ); + let nested_verify_circuit_prover = VerifyCircuitProver::new(nested_verify_prover); + + let encoded_vs_proof = vs_proof.encode_to_vec()?; + let nested_def_proof = nested_verify_circuit_prover.prove(&encoded_vs_proof); + + let vk = nested_verify_circuit_prover.get_vk(); + let engine = E::new(vk.inner.params.clone()); + engine.verify(&vk, &nested_def_proof)?; + + Ok(()) +} + +#[test] +fn test_verify_stark_path_sdk_can_verify_own_proofs() -> Result<()> { + setup_tracing(); + let n_stack = 19; + let app_params = app_params_with_100_bits_security(DEFAULT_APP_L_SKIP + n_stack); + let agg_params = AggregationSystemParams::default(); + let sdk = make_verify_stark_path_sdk(app_params, agg_params)?; + let agg_vk = sdk.agg_vk().as_ref().clone(); + + let vs_elf = Elf::decode( + include_bytes!("../programs/examples/verify-stark.elf"), + MEM_SIZE as u32, + )?; + let vs_exe = sdk.convert_to_exe(vs_elf)?; + + let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&sdk)?; + assert!(fib_proof.deferral_merkle_proofs.is_some(),); + Sdk::verify_proof(agg_vk.clone(), fib_baseline.clone(), &fib_proof)?; + + let (vs_stdin, def_input) = make_verify_stark_inputs(&sdk, &fib_proof, fib_baseline)?; + let (vs_proof, vs_baseline) = sdk.prove(vs_exe.clone(), vs_stdin, &[def_input])?; + assert!(vs_proof.deferral_merkle_proofs.is_some(),); + Sdk::verify_proof(agg_vk.clone(), vs_baseline.clone(), &vs_proof)?; + + let (vs2_stdin, vs2_def_input) = make_verify_stark_inputs(&sdk, &vs_proof, vs_baseline)?; + let (vs2_proof, vs2_baseline) = sdk.prove(vs_exe, vs2_stdin, &[vs2_def_input])?; + assert!(vs2_proof.deferral_merkle_proofs.is_some(),); + Sdk::verify_proof(agg_vk, vs2_baseline, &vs2_proof)?; + + Ok(()) +} + +#[test] +fn test_deferrals_enabled_without_usage() -> Result<()> { + setup_tracing(); + let (fib_sdk, app_params, agg_params) = make_fib_sdk(); + let sdk = make_deferral_enabled_sdk(&fib_sdk, app_params, agg_params)?; + + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let app_exe = sdk.convert_to_exe(elf)?; + + let n = 1000u64; + let mut stdin = StdIn::default(); + stdin.write(&n); + + let mut evm_prover = sdk.evm_prover_without_halo2(app_exe)?; + let proof = evm_prover.prove_root(stdin, &[])?; + + // ---- Step 3: Verify the final result ---- + let vk = evm_prover.root_prover.0.get_vk(); + let engine = RootE::new(vk.inner.params.clone()); + engine.verify(&vk, &proof)?; + + Ok(()) +} + +#[test] +fn test_prove_mixed_vm_def_depth_mismatch() -> Result<()> { + setup_tracing(); + let (fib_sdk, app_params, agg_params) = make_fib_sdk(); + let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; + let (vs_sdk, vs_stdin, def_input) = + make_deferral_sdk(&fib_sdk, fib_proof, fib_baseline, app_params, agg_params)?; + + let vs_elf = Elf::decode( + include_bytes!("../programs/examples/verify-stark.elf"), + MEM_SIZE as u32, + )?; + let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; + + // ---- Step 1: Generate base VM and deferral proofs ---- + let agg_prover = vs_sdk.agg_prover(); + let app_proof = vs_sdk.app_prover(vs_exe)?.prove(vs_stdin)?; + let (vm_proof, mut internal_layer_metadata) = agg_prover.prove_vm(app_proof)?; + + // We assume that the verify-stark program is small enough where only a single + // internal_recursive layer is needed to fully aggregate its proof. + assert_eq!(internal_layer_metadata.internal_recursive_layer, 1); + + let def_prover = vs_sdk.def_path_prover.unwrap(); + let def_hook_proofs = def_prover.deferral_prover.prove(&[def_input])?; + let (def_proof, mut def_internal_recursive_layer) = + def_prover.agg_prover.prove_def(def_hook_proofs)?; + assert_eq!(def_internal_recursive_layer, 1); + + // ---- Step 2: Generate mixed proof with wrapped VM proof ---- + let mut wrapped_vm_metadata = internal_layer_metadata.clone(); + let mut wrapped_vm_proof = vm_proof.clone(); + for _ in 0..2 { + wrapped_vm_proof = agg_prover.wrap_proof(wrapped_vm_proof, &mut wrapped_vm_metadata)?; + } + let wrapped_vm_mixed_proof = agg_prover.prove_mixed( + wrapped_vm_proof, + def_proof.clone(), + &mut wrapped_vm_metadata, + def_internal_recursive_layer, + )?; + + // ---- Step 3: Generate mixed proof with wrapped deferral proof ---- + let wrapped_def_proof = match def_proof { + DeferralProof::Present(mut p) => { + for _ in 0..2 { + p = agg_prover.wrap_def_inner(p, def_internal_recursive_layer)?; + def_internal_recursive_layer += 1; + } + DeferralProof::Present(p) + } + DeferralProof::Absent(_) => panic!("expected DeferralProof::Present"), + }; + let wrapped_def_mixed_proof = agg_prover.prove_mixed( + vm_proof, + wrapped_def_proof, + &mut internal_layer_metadata, + def_internal_recursive_layer, + )?; + + // ---- Step 4: Verify mixed proofs ---- + let vk = agg_prover.internal_recursive_prover.get_vk(); + let engine = E::new(vk.inner.params.clone()); + engine.verify(&vk, &wrapped_vm_mixed_proof.inner)?; + engine.verify(&vk, &wrapped_def_mixed_proof.inner)?; + + Ok(()) +} + +/// Cell-count profiling test for the static verifier circuit using a production root proof. +/// +/// Root verifier params match `pipeline_cell_count_profiling` in static-verifier crate. +/// The root proof is generated from a full SDK aggregation pipeline and cached to disk. +/// +/// Run with: +/// ```sh +/// OPENVM_CACHE_DIR=cache OPENVM_PROFILE_DIR=profile \ +/// cargo nextest run --cargo-profile=fast -p openvm-sdk --features cuda,cell-profiling \ +/// -- sdk_static_verifier_cell_profiling +/// ``` +#[cfg(feature = "cell-profiling")] +#[test] +fn sdk_static_verifier_cell_profiling() -> Result<()> { + use std::path::Path; + + use halo2_base::gates::circuit::{builder::BaseCircuitBuilder, CircuitBuilderStage}; + use openvm::platform::memory::MEM_SIZE; + use openvm_continuations::{CommitBytes, RootSC}; + use openvm_stark_backend::{ + codec::{Decode, Encode}, + proof::Proof, + }; + use openvm_stark_sdk::config::root_params_with_100_bits_security; + use openvm_static_verifier::{ + compute_dag_onion_commit, + field::baby_bear::{BabyBearChip, BabyBearExtChip}, + log_heights_per_air_from_proof, StaticVerifierCircuit, + }; + + use crate::{ + config::{AggregationSystemParams, DEFAULT_APP_L_SKIP}, + keygen::dummy::compute_root_proof_heights, + prover::{EvmProver, RootProver}, + Sdk, StdIn, + }; + + // Root verifier params matching pipeline_cell_count_profiling in static-verifier + let root_params = root_params_with_100_bits_security(); + let cache_dir = std::env::var("OPENVM_CACHE_DIR").unwrap_or_else(|_| "cache".to_string()); + std::fs::create_dir_all(&cache_dir)?; + + let proof_path = format!("{cache_dir}/sdk_root_proof.bin"); + let vk_path = format!("{cache_dir}/sdk_root_vk.bin"); + let commit_path = format!("{cache_dir}/sdk_onion_commit.bin"); + + let (root_vk, root_proof, onion_commit) = + if Path::new(&proof_path).exists() && Path::new(&vk_path).exists() { + eprintln!("Loading cached root proof from {cache_dir}/"); + let proof_bytes = std::fs::read(&proof_path)?; + let root_proof = Proof::::decode_from_bytes(&proof_bytes)?; + + let vk_bytes = std::fs::read(&vk_path)?; + let root_vk = bitcode::deserialize(&vk_bytes) + .map_err(|e| eyre::eyre!("failed to deserialize root VK: {e}"))?; + + let commit_bytes: [u8; 32] = std::fs::read(&commit_path)? + .try_into() + .map_err(|_| eyre::eyre!("invalid commit file"))?; + let onion_commit = CommitBytes::new(commit_bytes).into(); + + (root_vk, root_proof, onion_commit) + } else { + eprintln!("Generating root proof via SDK pipeline (this takes a while)..."); + let n_stack = 19; + let app_params = openvm_stark_sdk::config::app_params_with_100_bits_security( + DEFAULT_APP_L_SKIP + n_stack, + ); + let agg_params = AggregationSystemParams::default(); + + let elf = Elf::decode( + include_bytes!("../programs/examples/fibonacci.elf"), + MEM_SIZE as u32, + )?; + let sdk = Sdk::riscv64(app_params, agg_params); + let app_exe = sdk.convert_to_exe(elf)?; + + // Compute trace heights for root prover with profiling params + let system_config = sdk.app_config().app_vm_config.as_ref(); + let agg_prover = sdk.agg_prover(); + let (trace_heights, root_pk) = compute_root_proof_heights::( + sdk.app_vm_builder().clone(), + &sdk.app_pk().app_vm_pk, + agg_prover.clone(), + root_params.clone(), + None, + )?; + + let ir_vk = agg_prover.internal_recursive_prover.get_vk(); + let ir_pcs_data = agg_prover + .internal_recursive_prover + .get_self_vk_pcs_data() + .unwrap(); + let vk_commit: CommitBytes = ir_pcs_data.commitment.into(); + let onion_commit = compute_dag_onion_commit(&ir_vk); + + let memory_dimensions = system_config.memory_config.memory_dimensions(); + let num_user_pvs = system_config.num_public_values; + + let root_prover = Arc::new(RootProver::from_pk( + ir_vk, + vk_commit, + root_pk, + memory_dimensions, + num_user_pvs, + None, + Some(trace_heights), + )); + + let mut evm_prover = EvmProver::::new( + sdk.app_vm_builder().clone(), + &sdk.app_pk().app_vm_pk, + app_exe, + agg_prover, + None, + root_prover.clone(), + None, + )?; + + let n = 100u64; + let mut stdin = StdIn::default(); + stdin.write(&n); + + let root_proof = evm_prover.prove_root(stdin, &[])?; + let root_vk_arc = root_prover.0.get_vk(); + let root_vk = root_vk_arc.as_ref().clone(); + + // Verify the root proof + let engine = RootE::new(root_vk.inner.params.clone()); + engine.verify(&root_vk, &root_proof)?; + + // Cache to disk + eprintln!("Caching root proof to {cache_dir}/"); + std::fs::write(&proof_path, root_proof.encode_to_vec()?)?; + std::fs::write( + &vk_path, + bitcode::serialize(&root_vk) + .map_err(|e| eyre::eyre!("failed to serialize root VK: {e}"))?, + )?; + std::fs::write(&commit_path, CommitBytes::from(onion_commit).as_slice())?; + + (root_vk, root_proof, onion_commit) + }; + + // Run static verifier cell profiling + eprintln!("Running static verifier cell profiling..."); + let log_heights = log_heights_per_air_from_proof(&root_proof); + + let circuit = StaticVerifierCircuit::try_new(root_vk, onion_commit, &log_heights) + .expect("Failed to construct StaticVerifierCircuit"); + + let profile_dir = std::env::var("OPENVM_PROFILE_DIR").unwrap_or_else(|_| "profile".to_string()); + std::env::set_var("OPENVM_PROFILE_DIR", &profile_dir); + + let mut builder = BaseCircuitBuilder::from_stage(CircuitBuilderStage::Mock) + .use_k(22) + .use_lookup_bits(21) + .use_instance_columns(0); + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + + let initial_cells = ctx.advice.len(); + circuit.populate_verify_stark_constraints(ctx, &ext_chip, &root_proof); + let final_cells = ctx.advice.len(); + eprintln!( + "Static verifier cell count: {} (delta: {})", + final_cells, + final_cells - initial_cells + ); + assert!( + final_cells > initial_cells, + "expected advice cells to increase" + ); + + Ok(()) +} diff --git a/patches/openvm-sdk/src/types.rs b/patches/openvm-sdk/src/types.rs new file mode 100644 index 00000000..7305a366 --- /dev/null +++ b/patches/openvm-sdk/src/types.rs @@ -0,0 +1,502 @@ +use std::sync::Arc; + +use derive_more::derive::From; +use eyre::Result; +use openvm::platform::memory::MEM_SIZE; +#[cfg(feature = "evm-prove")] +use openvm_circuit::arch::U16_CELL_SIZE; +use openvm_circuit::{ + arch::instructions::exe::VmExe, + system::memory::{dimensions::MemoryDimensions, merkle::public_values::UserPublicValuesProof}, +}; +use openvm_continuations::CommitBytes; +use openvm_stark_backend::{ + codec::{Decode, Encode}, + proof::Proof, +}; +use openvm_transpiler::elf::Elf; +use openvm_verify_stark_host::{ + deferral::DeferralMerkleProofs, pvs::VkCommit, vk::VerificationBaseline, VmStarkProof, +}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::OPENVM_VERSION; + +#[derive(From)] +pub enum ExecutableFormat { + Elf(Elf), + VmExe(VmExe), + SharedVmExe(Arc>), +} + +impl<'a> From<&'a [u8]> for ExecutableFormat { + fn from(bytes: &'a [u8]) -> Self { + let elf = Elf::decode(bytes, MEM_SIZE.try_into().unwrap()).expect("Invalid ELF bytes"); + ExecutableFormat::Elf(elf) + } +} +impl From> for ExecutableFormat { + fn from(bytes: Vec) -> Self { + ExecutableFormat::from(&bytes[..]) + } +} + +/// Number of bytes in a Bn254. +#[allow(dead_code)] +pub(crate) const BN254_BYTES: usize = 32; +/// Number of Bn254 in `accumulator` field (KZG accumulator). +pub const NUM_BN254_ACCUMULATOR: usize = 12; +/// Number of Bn254 in `proof` field for a circuit with only 1 advice column. +#[cfg(feature = "evm-prove")] +#[allow(dead_code)] +pub(crate) const NUM_BN254_PROOF: usize = 43; + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ProofData { + #[serde_as(as = "serde_with::hex::Hex")] + /// KZG accumulator. + pub accumulator: Vec, + #[serde_as(as = "serde_with::hex::Hex")] + /// Bn254 proof in little-endian bytes. The circuit only has 1 advice column, so the proof is + /// of length `NUM_BN254_PROOF * BN254_BYTES`. + pub proof: Vec, +} + +// =================== EVM types (evm-prove feature) =================== + +#[cfg(feature = "evm-prove")] +pub use openvm_static_verifier::wrapper::EvmVerifierByteCode; + +#[cfg(feature = "evm-prove")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct EvmHalo2Verifier { + pub halo2_verifier_code: String, + pub openvm_verifier_code: String, + pub openvm_verifier_interface: String, + pub artifact: EvmVerifierByteCode, +} + +/// Custom serde for CommitBytes as hex-encoded [u8; 32]. +pub mod hex_bytes32 { + use openvm_continuations::CommitBytes; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(val: &CommitBytes, s: S) -> Result { + format!("0x{}", hex::encode(val.as_slice())).serialize(s) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result { + let hex_str = String::deserialize(d)?; + let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str); + let bytes: [u8; 32] = hex::decode(hex_str) + .map_err(serde::de::Error::custom)? + .try_into() + .map_err(|_| serde::de::Error::custom("expected 32 bytes"))?; + Ok(CommitBytes::new(bytes)) + } +} + +/// Application execution commitment pair (big-endian 32-byte values). +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub struct AppExecutionCommit { + #[serde(with = "hex_bytes32")] + pub app_exe_commit: openvm_continuations::CommitBytes, + #[serde(with = "hex_bytes32")] + pub app_vm_commit: openvm_continuations::CommitBytes, +} + +#[cfg(feature = "evm-prove")] +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EvmProof { + /// The openvm major and minor version v{}.{}. The proof format will not change on patch + /// versions. + pub version: String, + #[serde(flatten)] + /// Bn254 public value app commits. + pub app_commit: AppExecutionCommit, + #[serde_as(as = "serde_with::hex::Hex")] + /// User public values packed into bytes. + pub user_public_values: Vec, + /// Byte encoding of the `proof`. + pub proof_data: ProofData, +} + +#[cfg(feature = "evm-prove")] +#[derive(Debug, thiserror::Error)] +pub enum EvmProofConversionError { + #[error("Invalid length of instances: expected at least 3, got {0}")] + InvalidLengthInstances(usize), + #[error("Invalid length of user public values")] + InvalidUserPublicValuesLength, +} + +#[cfg(feature = "evm-prove")] +impl EvmProof { + #[cfg(feature = "evm-verify")] + /// Return bytes calldata to be passed to the verifier contract. + pub fn verifier_calldata(self) -> Vec { + use alloy_sol_types::SolCall; + + use crate::solidity::IOpenVmHalo2Verifier; + + let EvmProof { + user_public_values, + app_commit, + proof_data, + version: _, + } = self; + + let ProofData { accumulator, proof } = proof_data; + + let mut proof_data_bytes = accumulator; + proof_data_bytes.extend(proof); + + IOpenVmHalo2Verifier::verifyCall { + publicValues: user_public_values.into(), + proofData: proof_data_bytes.into(), + appExeCommit: (*app_commit.app_exe_commit.as_slice()).into(), + appVmCommit: (*app_commit.app_vm_commit.as_slice()).into(), + } + .abi_encode() + } + + #[cfg(feature = "evm-verify")] + pub fn fallback_calldata(&self) -> Vec { + let raw: openvm_static_verifier::keygen::RawEvmProof = self.clone().into(); + encode_raw_evm_proof_calldata(&raw) + } +} + +/// Encode a [`RawEvmProof`](openvm_static_verifier::keygen::RawEvmProof) as calldata for the +/// fallback (raw) verifier. +/// +/// Format: each instance as 32-byte big-endian, followed by raw proof bytes. +#[cfg(feature = "evm-verify")] +pub fn encode_raw_evm_proof_calldata( + proof: &openvm_static_verifier::keygen::RawEvmProof, +) -> Vec { + let mut calldata = Vec::new(); + for instance in &proof.instances { + // Fr::to_bytes() is little-endian; EVM expects big-endian + let mut bytes = instance.to_bytes(); + bytes.reverse(); + calldata.extend_from_slice(&bytes); + } + calldata.extend_from_slice(&proof.proof); + calldata +} + +/// Convert `RawEvmProof` → `EvmProof`. +/// +/// Instance layout (with KZG accumulator from wrapper circuit): +/// - `instances[0..12]`: KZG accumulator (12 Fr values) +/// - `instances[12]`: app_exe_commit (Fr) +/// - `instances[13]`: app_vm_commit (Fr) +/// - `instances[14..]`: user public values (each u16 limb as Fr) +#[cfg(feature = "evm-prove")] +impl From for EvmProof { + fn from(raw: openvm_static_verifier::keygen::RawEvmProof) -> Self { + use openvm_continuations::CommitBytes; + + let openvm_static_verifier::keygen::RawEvmProof { instances, proof } = raw; + assert!( + instances.len() > NUM_BN254_ACCUMULATOR + 2, + "RawEvmProof instances must have at least {} elements (accumulator + exe commit + vk commit)", + NUM_BN254_ACCUMULATOR + 2 + ); + + // instances[0..12] are the KZG accumulator + let accumulator = instances[0..NUM_BN254_ACCUMULATOR] + .iter() + .flat_map(|f| f.to_bytes()) + .collect::>(); + + // Reverse each 32-byte chunk for big-endian EVM format + let mut evm_accumulator = Vec::with_capacity(accumulator.len()); + accumulator + .chunks(BN254_BYTES) + .for_each(|chunk| evm_accumulator.extend(chunk.iter().rev().copied())); + + // instances[12] and [13] are Fr values encoding commits. + // Fr::to_bytes() returns 32 bytes in little-endian; CommitBytes expects big-endian. + let mut app_exe_bytes = instances[NUM_BN254_ACCUMULATOR].to_bytes(); + app_exe_bytes.reverse(); + let mut app_vm_bytes = instances[NUM_BN254_ACCUMULATOR + 1].to_bytes(); + app_vm_bytes.reverse(); + + let user_public_values = instances[NUM_BN254_ACCUMULATOR + 2..] + .iter() + .flat_map(|f| { + let bytes = f.to_bytes(); + debug_assert!( + bytes[U16_CELL_SIZE..].iter().all(|&byte| byte == 0), + "user public value limb must fit in u16" + ); + std::array::from_fn::<_, U16_CELL_SIZE, _>(|i| bytes[i]) + }) + .collect::>(); + + let app_commit = AppExecutionCommit { + app_exe_commit: CommitBytes::new(app_exe_bytes), + app_vm_commit: CommitBytes::new(app_vm_bytes), + }; + + Self { + version: format!("v{OPENVM_VERSION}"), + app_commit, + user_public_values, + proof_data: ProofData { + accumulator: evm_accumulator, + proof, + }, + } + } +} + +/// Convert `EvmProof` → `RawEvmProof`. +#[cfg(feature = "evm-prove")] +impl From for openvm_static_verifier::keygen::RawEvmProof { + fn from(evm_proof: EvmProof) -> Self { + use openvm_static_verifier::Fr; + + let EvmProof { + app_commit, + user_public_values, + proof_data, + version: _, + } = evm_proof; + + let ProofData { accumulator, proof } = proof_data; + + // Reverse each 32-byte chunk from big-endian (EVM) to little-endian (Fr) + let mut reversed_accumulator = Vec::with_capacity(accumulator.len()); + accumulator + .chunks(BN254_BYTES) + .for_each(|chunk| reversed_accumulator.extend(chunk.iter().rev().copied())); + + // CommitBytes is big-endian; Fr::from_bytes expects little-endian + let mut app_exe_bytes = *app_commit.app_exe_commit.as_slice(); + app_exe_bytes.reverse(); + let app_exe_fr = Fr::from_bytes(&app_exe_bytes).unwrap(); + + let mut app_vm_bytes = *app_commit.app_vm_commit.as_slice(); + app_vm_bytes.reverse(); + let app_vm_fr = Fr::from_bytes(&app_vm_bytes).unwrap(); + + assert!( + user_public_values.len().is_multiple_of(U16_CELL_SIZE), + "user public values length must be a multiple of {U16_CELL_SIZE}" + ); + let user_pvs_frs: Vec = user_public_values + .chunks_exact(U16_CELL_SIZE) + .map(|limb| { + let mut bytes = [0u8; 32]; + bytes[..U16_CELL_SIZE].copy_from_slice(limb); + Fr::from_bytes(&bytes).unwrap() + }) + .collect(); + + // Reconstruct instances: accumulator + commits + user PVs + let mut instances = Vec::new(); + for chunk in reversed_accumulator.chunks(BN254_BYTES) { + let c: [u8; 32] = chunk.try_into().unwrap(); + instances.push(Fr::from_bytes(&c).unwrap()); + } + instances.push(app_exe_fr); + instances.push(app_vm_fr); + instances.extend(user_pvs_frs); + + openvm_static_verifier::keygen::RawEvmProof { instances, proof } + } +} + +// =================== Non-EVM types =================== + +/// Struct purely for encoding and decoding of [VmStarkProof]. +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize, Encode, Decode)] +pub struct VersionedVmStarkProof { + /// The openvm major and minor version v{}.{}. The proof format will not change on patch + /// versions. + pub version: String, + #[serde_as(as = "serde_with::hex::Hex")] + pub proof: Vec, + #[serde_as(as = "serde_with::hex::Hex")] + pub user_pvs_proof: Vec, + #[serde(default)] + #[serde_as(as = "Option")] + pub deferral_merkle_proofs: Option>, +} + +impl VersionedVmStarkProof { + pub fn new(proof: VmStarkProof) -> Result { + Ok(Self { + version: format!("v{}", OPENVM_VERSION), + proof: proof.inner.encode_to_vec()?, + user_pvs_proof: { + let mut buf = Vec::new(); + proof.user_pvs_proof.encode::(&mut buf)?; + buf + }, + deferral_merkle_proofs: proof + .deferral_merkle_proofs + .map(|ref dmp| { + let mut buf = Vec::new(); + dmp.encode(&mut buf)?; + Ok::<_, std::io::Error>(buf) + }) + .transpose()?, + }) + } +} + +#[cfg(all(test, feature = "evm-prove"))] +mod tests { + use halo2_base::halo2_proofs::arithmetic::Field; + use openvm_static_verifier::{keygen::RawEvmProof, Fr}; + + use super::{EvmProof, NUM_BN254_ACCUMULATOR, U16_CELL_SIZE}; + + fn fr_from_u16(value: u16) -> Fr { + let mut bytes = [0u8; 32]; + bytes[..U16_CELL_SIZE].copy_from_slice(&value.to_le_bytes()); + Fr::from_bytes(&bytes).unwrap() + } + + #[test] + fn evm_proof_roundtrips_u16_public_values() { + let mut instances = vec![Fr::ZERO; NUM_BN254_ACCUMULATOR + 2]; + instances.extend([fr_from_u16(0x1234), fr_from_u16(0xabcd)]); + let raw = RawEvmProof { + instances, + proof: vec![1, 2, 3], + }; + + let proof = EvmProof::from(raw.clone()); + assert_eq!(proof.user_public_values, [0x34, 0x12, 0xcd, 0xab]); + + let roundtrip = RawEvmProof::from(proof); + assert_eq!(roundtrip.instances, raw.instances); + assert_eq!(roundtrip.proof, raw.proof); + } +} + +impl TryFrom for VmStarkProof { + type Error = std::io::Error; + fn try_from(proof: VersionedVmStarkProof) -> Result { + let VersionedVmStarkProof { + proof, + user_pvs_proof, + deferral_merkle_proofs, + .. + } = proof; + Ok(Self { + inner: Proof::::decode_from_bytes(&proof)?, + user_pvs_proof: UserPublicValuesProof::decode::( + &mut std::io::Cursor::new(&user_pvs_proof), + )?, + deferral_merkle_proofs: deferral_merkle_proofs + .map(|bytes| DeferralMerkleProofs::decode(&mut std::io::Cursor::new(&bytes))) + .transpose()?, + }) + } +} + +// =================== Verification baseline JSON types =================== + +/// Hex-formatted [`VkCommit`] for JSON serialization. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct VkCommitJson { + #[serde(with = "hex_bytes32")] + pub cached_commit: CommitBytes, + #[serde(with = "hex_bytes32")] + pub vk_pre_hash: CommitBytes, +} + +/// Hex-formatted [`VerificationBaseline`] for JSON serialization. +/// +/// Mirrors [`VerificationBaseline`] but serializes all commit fields as `0x`-prefixed hex strings, +/// consistent with [`AppExecutionCommit`]. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct VerificationBaselineJson { + #[serde(with = "hex_bytes32")] + pub app_exe_commit: CommitBytes, + pub memory_dimensions: MemoryDimensions, + pub num_user_pvs: usize, + pub app_vk_commit: VkCommitJson, + pub leaf_vk_commit: VkCommitJson, + pub internal_for_leaf_vk_commit: VkCommitJson, + pub internal_recursive_vk_commit: VkCommitJson, + #[serde(with = "option_hex_bytes32")] + pub expected_def_hook_commit: Option, +} + +impl From for VerificationBaselineJson { + fn from(b: VerificationBaseline) -> Self { + let vk = |d: VkCommit| VkCommitJson { + cached_commit: CommitBytes::from(d.cached_commit), + vk_pre_hash: CommitBytes::from(d.vk_pre_hash), + }; + Self { + app_exe_commit: CommitBytes::from(b.app_exe_commit), + memory_dimensions: b.memory_dimensions, + num_user_pvs: b.num_user_pvs, + app_vk_commit: vk(b.app_vk_commit), + leaf_vk_commit: vk(b.leaf_vk_commit), + internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit), + internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit), + expected_def_hook_commit: b.expected_def_hook_commit.map(CommitBytes::from), + } + } +} + +impl From for VerificationBaseline { + fn from(b: VerificationBaselineJson) -> Self { + use openvm_verify_stark_host::pvs::VkCommit; + let vk = |d: VkCommitJson| VkCommit { + cached_commit: d.cached_commit.into(), + vk_pre_hash: d.vk_pre_hash.into(), + }; + Self { + app_exe_commit: b.app_exe_commit.into(), + memory_dimensions: b.memory_dimensions, + num_user_pvs: b.num_user_pvs, + app_vk_commit: vk(b.app_vk_commit), + leaf_vk_commit: vk(b.leaf_vk_commit), + internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit), + internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit), + expected_def_hook_commit: b.expected_def_hook_commit.map(|c| c.into()), + } + } +} + +/// Custom serde for `Option` as hex-encoded `[u8; 32]`. +pub mod option_hex_bytes32 { + use openvm_continuations::CommitBytes; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(val: &Option, s: S) -> Result { + match val { + Some(v) => super::hex_bytes32::serialize(v, s), + None => s.serialize_none(), + } + } + + pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { + let opt: Option = Option::deserialize(d)?; + match opt { + Some(hex_str) => { + let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str); + let bytes: [u8; 32] = hex::decode(hex_str) + .map_err(serde::de::Error::custom)? + .try_into() + .map_err(|_| serde::de::Error::custom("expected 32 bytes"))?; + Ok(Some(CommitBytes::new(bytes))) + } + None => Ok(None), + } + } +} diff --git a/patches/openvm-sdk/src/util.rs b/patches/openvm-sdk/src/util.rs new file mode 100644 index 00000000..5d260941 --- /dev/null +++ b/patches/openvm-sdk/src/util.rs @@ -0,0 +1,23 @@ +use std::cmp::Ordering; + +use openvm_circuit::arch::SystemConfig; + +pub fn check_max_constraint_degrees(config: &SystemConfig, max_constraint_degree: usize) { + match config.max_constraint_degree.cmp(&max_constraint_degree) { + Ordering::Greater => { + tracing::warn!( + "config.max_constraint_degree ({}) > vk max_constraint_degree() ({})", + config.max_constraint_degree, + max_constraint_degree + ); + } + Ordering::Less => { + tracing::info!( + "config.max_constraint_degree ({}) < vk max_constraint_degree() ({})", + config.max_constraint_degree, + max_constraint_degree + ); + } + Ordering::Equal => {} + } +} diff --git a/patches/openvm-static-verifier/Cargo.toml b/patches/openvm-static-verifier/Cargo.toml new file mode 100644 index 00000000..6f6e1356 --- /dev/null +++ b/patches/openvm-static-verifier/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "openvm-static-verifier" +version = "2.0.0-beta.2" +edition = "2021" +rust-version = "1.91.1" +authors = ["OpenVM Authors"] +homepage = "https://openvm.dev" +repository = "https://github.com/openvm-org/" +license = "MIT OR Apache-2.0" + +[dependencies] +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, features = ["baby-bear-bn254-poseidon2"] } +openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, optional = true, features = ["baby-bear-bn254-poseidon2"] } +openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } +openvm-cpu-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false, features = ["root-prover"] } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.5.2", default-features = false, features = ["halo2-axiom"] } +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.2.4", default-features = false, features = ["loader_evm"], optional = true } + +rand_chacha = "0.3" +once_cell = { version = "1.20", default-features = false, optional = true } +serde = { version = "1.0.201", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.117", optional = true } +serde_with = { version = "3.11.0", features = ["hex"], optional = true } +itertools = { version = "0.14.0", default-features = false } +num-bigint = { version = "0.4.6", default-features = false } +num-integer = { version = "0.1.46", default-features = false } +tracing = "0.1.40" +inferno = { version = "0.12", default-features = false, optional = true } + +[dev-dependencies] +openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", features = ["test-utils"] } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, features = ["cpu-backend"] } + +[features] +default = [] +# Patched: do NOT forward snark-verifier-sdk/cuda so Halo2 SNARK stays on CPU +# while OpenVM STARK proving uses the GPU backend. +cuda = ["dep:openvm-cuda-backend"] +evm-prove = ["dep:snark-verifier-sdk", "dep:serde_with", "dep:once_cell", "dep:serde_json"] +evm-verify = ["evm-prove", "snark-verifier-sdk/revm"] +cell-profiling = ["dep:inferno"] diff --git a/patches/openvm-static-verifier/src/circuit.rs b/patches/openvm-static-verifier/src/circuit.rs new file mode 100644 index 00000000..d2440c73 --- /dev/null +++ b/patches/openvm-static-verifier/src/circuit.rs @@ -0,0 +1,302 @@ +//! Host-fixed parameters for the static verifier Halo2 circuit (see crate `lib.rs`). + +use core::cmp::Reverse; +use std::{borrow::Borrow, fmt, sync::Arc}; + +use halo2_base::{ + gates::circuit::builder::BaseCircuitBuilder, halo2_proofs::halo2curves::bn256::Fr, Context, +}; +use itertools::Itertools; +use openvm_cpu_backend::CpuBackend; +use openvm_recursion_circuit::{ + batch_constraint::expr_eval::DagCommitPvs, + system::{VerifierConfig, VerifierSubCircuit, VerifierTraceGen}, +}; +use openvm_stark_sdk::{ + config::{ + baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig, + baby_bear_poseidon2::{BabyBearPoseidon2Config, Digest as InnerDigest}, + }, + openvm_stark_backend::{ + keygen::types::{MultiStarkVerifyingKey, MultiStarkVerifyingKey0}, + proof::Proof, + prover::stacked_pcs::StackedLayout, + }, +}; +use openvm_verify_stark_host::pvs::CONSTRAINT_EVAL_AIR_ID; +use serde::{Deserialize, Serialize}; + +use crate::{ + field::baby_bear::{BabyBearChip, BabyBearExtChip}, + stages::{ + full_pipeline::{ + constrained_verify, extract_public_values, load_proof_wire, ProofWire, + StaticVerifierPvs, + }, + proof_shape::trace_id_order_from_static_heights, + }, +}; + +/// Builds stacked PCS layouts for the static verifier from VK widths and fixed per-air log heights. +pub(crate) fn build_stacked_layouts_for_static_vk( + mvk0: &MultiStarkVerifyingKey0, + log_heights_per_air: &[usize], +) -> Vec { + let l_skip = mvk0.params.l_skip; + assert_eq!( + log_heights_per_air.len(), + mvk0.per_air.len(), + "log_heights_per_air length must match VK per_air count" + ); + let mut per_trace = mvk0 + .per_air + .iter() + .enumerate() + .map(|(air_idx, vk)| (air_idx, vk, log_heights_per_air[air_idx])) + .collect::>(); + per_trace.sort_by_key(|(_, _, log_height)| Reverse(*log_height)); + + let common_main_layout = StackedLayout::new( + l_skip, + mvk0.params.n_stack + l_skip, + per_trace + .iter() + .map(|(_, vk, log_height)| (vk.params.width.common_main, *log_height)) + .collect::>(), + ) + .expect("stacked layout for common main"); + let other_layouts = per_trace + .iter() + .flat_map(|(_, vk, log_height)| { + vk.params + .width + .preprocessed + .iter() + .chain(&vk.params.width.cached_mains) + .copied() + .map(|width| (width, *log_height)) + .collect::>() + }) + .map(|sorted| { + StackedLayout::new(l_skip, mvk0.params.n_stack + l_skip, vec![sorted]) + .expect("stacked layout for auxiliary column") + }) + .collect::>(); + core::iter::once(common_main_layout) + .chain(other_layouts) + .collect::>() +} + +/// Error building [`StaticVerifierCircuit`] from fixed per-AIR log heights. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum StaticCircuitParamsError { + LogHeightsLenMismatch { expected: usize, got: usize }, +} + +impl fmt::Display for StaticCircuitParamsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::LogHeightsLenMismatch { expected, got } => { + write!( + f, + "log_heights_per_air length {got} != VK per_air length {expected}" + ) + } + } + } +} + +impl std::error::Error for StaticCircuitParamsError {} + +/// Parameters fixed host-side for the static verifier (child VK, trace heights, AIR permutation). +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct StaticVerifierCircuit { + pub root_vk: MultiStarkVerifyingKey, + /// The [RootConfig] hash onion commitment to the internal-recursive verifier circuit's + /// symbolic constraints DAG. This is exposed as a public value by the DagCommitSubAir within + /// the SymbolicExpressionAir in the RootVerifierCircuit. + /// + /// This value can be obtained from `cached_trace_record.dag_commit_info.commit` in the + /// `RootProver`. + pub internal_recursive_dag_onion_commit: InnerDigest, + pub log_heights_per_air: Vec, + pub trace_id_to_air_id: Vec, + pub stacked_layouts: Vec, +} + +impl StaticVerifierCircuit { + /// Build static parameters from a child VK and the per-AIR trace log heights for this circuit. + /// + /// `log_heights_per_air[i]` is the log₂ trace height for AIR `i` (same indexing as the child + /// VK's `per_air`). Trace IDs are ordered by descending height (tie-break: lower `air_id` + /// first). + pub fn try_new( + root_vk: MultiStarkVerifyingKey, + internal_recursive_dag_onion_commit: InnerDigest, + log_heights_per_air: &[usize], + ) -> Result { + let n = root_vk.inner.per_air.len(); + if log_heights_per_air.len() != n { + return Err(StaticCircuitParamsError::LogHeightsLenMismatch { + expected: n, + got: log_heights_per_air.len(), + }); + } + let log_heights_per_air = log_heights_per_air.to_vec(); + let trace_id_to_air_id = + trace_id_order_from_static_heights(&root_vk.inner, &log_heights_per_air); + let stacked_layouts = + build_stacked_layouts_for_static_vk(&root_vk.inner, &log_heights_per_air); + Ok(Self { + root_vk, + internal_recursive_dag_onion_commit, + log_heights_per_air, + trace_id_to_air_id, + stacked_layouts, + }) + } + + /// STARK verification constraints only: load the proof witness and run + /// `constrained_verify`. + /// + /// Does **not** check proof public values or cached trace commitments, which requires the proof + /// to have a particular shape following the VM Continuations framework. + /// + /// This function should be used internally or for testing only. + /// Production uses with the continuations framework **must** use [`Self::populate`] instead. + pub fn populate_verify_stark_constraints( + &self, + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + proof: &Proof, + ) -> ProofWire { + let mut profiler = crate::profiling::CellProfiler::new("static_verifier", ctx.advice.len()); + + profiler.push("load_proof_wire", ctx.advice.len()); + let proof_wire = load_proof_wire(ctx, ext_chip, proof, &self.log_heights_per_air); + profiler.pop(ctx.advice.len()); + + profiler.push("constrained_verify", ctx.advice.len()); + constrained_verify( + ctx, + ext_chip, + &self.root_vk, + &proof_wire, + &self.trace_id_to_air_id, + &self.log_heights_per_air, + &self.stacked_layouts, + ); + profiler.pop(ctx.advice.len()); + + profiler.print(ctx.advice.len()); + + #[cfg(feature = "cell-profiling")] + if let Ok(dir) = std::env::var("OPENVM_PROFILE_DIR") { + let _ = std::fs::create_dir_all(&dir); + profiler.write_flamegraph( + &format!("{dir}/static_verifier_constraints.svg"), + "Static Verifier Constraints", + ctx.advice.len(), + ); + profiler.write_flamegraph_reversed( + &format!("{dir}/static_verifier_constraints_rev.svg"), + "Static Verifier Constraints (reversed)", + ctx.advice.len(), + ); + } + + proof_wire + } + + /// Populate a builder with the static verifier constraints and return the public values. + pub fn populate( + &self, + builder: &mut BaseCircuitBuilder, + proof: &Proof, + ) -> StaticVerifierPvs { + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + + let mut profiler = crate::profiling::CellProfiler::new("populate", ctx.advice.len()); + + profiler.push("verify_stark_constraints", ctx.advice.len()); + let proof_wire = &self.populate_verify_stark_constraints(ctx, &ext_chip, proof); + profiler.pop(ctx.advice.len()); + + debug_assert!( + proof_wire + .cached_commitment_roots + .iter() + .all(|commits| commits.is_empty()), + "RootVerifierCircuit has no cached trace" + ); + profiler.push("pin_dag_onion_commit", ctx.advice.len()); + let &DagCommitPvs::<_> { + commit: onion_commit, + } = proof_wire.public_values[CONSTRAINT_EVAL_AIR_ID] + .as_slice() + .borrow(); + for (bb_wire, bb_const) in onion_commit + .into_iter() + .zip_eq(self.internal_recursive_dag_onion_commit) + { + let loaded_const = ext_chip.base().load_constant(ctx, bb_const); + ext_chip + .base() + .assert_equal(ctx, bb_wire.into(), loaded_const); + } + profiler.pop(ctx.advice.len()); + + profiler.push("extract_public_values", ctx.advice.len()); + let pvs_wire = extract_public_values(ctx, ext_chip.base(), proof_wire); + profiler.pop(ctx.advice.len()); + + #[cfg(feature = "cell-profiling")] + if let Ok(dir) = std::env::var("OPENVM_PROFILE_DIR") { + let _ = std::fs::create_dir_all(&dir); + profiler.write_flamegraph( + &format!("{dir}/populate.svg"), + "Static Verifier Populate", + ctx.advice.len(), + ); + profiler.write_flamegraph_reversed( + &format!("{dir}/populate_rev.svg"), + "Static Verifier Populate (reversed)", + ctx.advice.len(), + ); + } + + let pvs_vec = pvs_wire.to_vec(); + let pvs_fr = pvs_vec.iter().map(|v| *v.value()).collect_vec(); + builder.assigned_instances[0].extend(pvs_vec); + + StaticVerifierPvs::from_slice(&pvs_fr) + } +} + +pub fn compute_dag_onion_commit( + internal_recursive_vk: &MultiStarkVerifyingKey, +) -> InnerDigest { + // Note: the MAX_NUM_PROOFS const generic does not impact the build_cached_trace_record function + // used internally below, but we use 1 to match the root circuit. The internal_recursive circuit + // itself uses MAX_NUM_PROOFS = 3, but here it is the child. + let verifier_circuit = VerifierSubCircuit::<1>::new_with_options( + Arc::new(internal_recursive_vk.clone()), + VerifierConfig { + continuations_enabled: true, + has_cached: false, + ..Default::default() + }, + ); + + // The ProverBackend and config used here also does not impact the generated CachedTraceRecord + let cached_trace_record = VerifierTraceGen::< + CpuBackend, + BabyBearPoseidon2Config, + (), + >::cached_trace_record(&verifier_circuit, internal_recursive_vk); + + // Despite the name, this returns the DAG onion commit for when there is no cached trace + cached_trace_record.dag_commit_info.unwrap().commit +} diff --git a/patches/openvm-static-verifier/src/codec.rs b/patches/openvm-static-verifier/src/codec.rs new file mode 100644 index 00000000..b849af36 --- /dev/null +++ b/patches/openvm-static-verifier/src/codec.rs @@ -0,0 +1,99 @@ +use std::io::{self, Read, Write}; + +use halo2_base::{ + gates::circuit::builder::BaseCircuitBuilder, + halo2_proofs::{ + halo2curves::bn256::{Fr, G1Affine}, + plonk::ProvingKey, + SerdeFormat, + }, +}; +use openvm_stark_sdk::openvm_stark_backend::codec::{Decode, Encode}; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::{ + keygen::StaticVerifierProvingKey, + prover::{Halo2ProvingMetadata, Halo2ProvingPinning}, + wrapper::Halo2WrapperProvingKey, +}; + +const MAX_JSON_SECTION_LEN: usize = 64 * 1024 * 1024; + +impl Encode for StaticVerifierProvingKey { + fn encode(&self, writer: &mut W) -> io::Result<()> { + write_json_section(writer, &(&self.circuit, &self.shape))?; + self.pinning.encode(writer) + } +} + +impl Decode for StaticVerifierProvingKey { + fn decode(reader: &mut R) -> io::Result { + let (circuit, shape) = read_json_section(reader)?; + let pinning = Halo2ProvingPinning::decode(reader)?; + Ok(Self { + circuit, + pinning, + shape, + }) + } +} + +impl Encode for Halo2WrapperProvingKey { + fn encode(&self, writer: &mut W) -> io::Result<()> { + self.pinning.encode(writer) + } +} + +impl Decode for Halo2WrapperProvingKey { + fn decode(reader: &mut R) -> io::Result { + Ok(Self { + pinning: Halo2ProvingPinning::decode(reader)?, + }) + } +} + +impl Encode for Halo2ProvingPinning { + fn encode(&self, writer: &mut W) -> io::Result<()> { + write_json_section(writer, &self.metadata)?; + self.pk.write(writer, SerdeFormat::RawBytes) + } +} + +impl Decode for Halo2ProvingPinning { + fn decode(reader: &mut R) -> io::Result { + let metadata: Halo2ProvingMetadata = read_json_section(reader)?; + let pk = ProvingKey::::read::<_, BaseCircuitBuilder>( + reader, + SerdeFormat::RawBytes, + metadata.config_params.clone(), + )?; + Ok(Self { pk, metadata }) + } +} + +// Each JSON section is length-prefixed because it is followed by raw Halo2 proving-key bytes. +fn write_json_section(writer: &mut W, value: &T) -> io::Result<()> { + let bytes = serde_json::to_vec(value).map_err(io::Error::other)?; + writer.write_all(&(bytes.len() as u64).to_le_bytes())?; + writer.write_all(&bytes) +} + +fn read_json_section(reader: &mut R) -> io::Result { + let mut len_bytes = [0u8; 8]; + reader.read_exact(&mut len_bytes)?; + let len = usize::try_from(u64::from_le_bytes(len_bytes)).map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidData, + "JSON section length overflows usize", + ) + })?; + if len > MAX_JSON_SECTION_LEN { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "JSON section is too large", + )); + } + let mut bytes = vec![0u8; len]; + reader.read_exact(&mut bytes)?; + serde_json::from_slice(&bytes).map_err(io::Error::other) +} diff --git a/patches/openvm-static-verifier/src/config.rs b/patches/openvm-static-verifier/src/config.rs new file mode 100644 index 00000000..a595d77e --- /dev/null +++ b/patches/openvm-static-verifier/src/config.rs @@ -0,0 +1,39 @@ +use halo2_base::gates::circuit::BaseCircuitParams; +use serde::{Deserialize, Serialize}; + +pub const STATIC_VERIFIER_NUM_ADVICE_COLS: usize = 1; +pub const STATIC_VERIFIER_LOOKUP_ADVICE_COLS: usize = 1; + +pub const DEFAULT_HALO2_VERIFIER_K: usize = 23; + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct StaticVerifierShape { + pub k: usize, + pub lookup_bits: usize, + pub minimum_rows: usize, + pub instance_columns: usize, +} + +impl Default for StaticVerifierShape { + fn default() -> Self { + Self { + k: DEFAULT_HALO2_VERIFIER_K, + lookup_bits: DEFAULT_HALO2_VERIFIER_K - 1, + minimum_rows: 20, + instance_columns: 1, + } + } +} + +impl StaticVerifierShape { + pub fn expected_phase0_params(&self) -> BaseCircuitParams { + BaseCircuitParams { + k: self.k, + num_advice_per_phase: vec![STATIC_VERIFIER_NUM_ADVICE_COLS], + num_fixed: 1, + num_lookup_advice_per_phase: vec![STATIC_VERIFIER_LOOKUP_ADVICE_COLS], + lookup_bits: Some(self.lookup_bits), + num_instance_columns: self.instance_columns, + } + } +} diff --git a/patches/openvm-static-verifier/src/context_tree.rs b/patches/openvm-static-verifier/src/context_tree.rs new file mode 100644 index 00000000..493895a7 --- /dev/null +++ b/patches/openvm-static-verifier/src/context_tree.rs @@ -0,0 +1,187 @@ +#![allow(dead_code)] + +use std::io::Write; + +use inferno::flamegraph::{self, Direction, Options}; +use tracing::Level; + +/// The hierarchy of contexts, and the cell count contributed by each one. +/// Useful for debugging and profiling Halo2 advice cell allocations. +/// +/// Adapted from plonky2 context_tree. +pub struct ContextTree { + /// The name of this scope. + name: String, + /// The level at which to log this scope and its children. + level: tracing::Level, + /// The cell count when this scope was created. + enter_cell_count: usize, + /// The cell count when this scope was destroyed, or None if it has not yet been destroyed. + exit_cell_count: Option, + /// Any child contexts. + children: Vec, +} + +impl ContextTree { + pub fn new() -> Self { + Self { + name: "root".to_string(), + level: Level::DEBUG, + enter_cell_count: 0, + exit_cell_count: None, + children: vec![], + } + } + + pub fn with_name(name: &str, enter_cell_count: usize) -> Self { + Self { + name: name.to_string(), + level: Level::DEBUG, + enter_cell_count, + exit_cell_count: None, + children: vec![], + } + } + + /// Whether this context is still in scope. + const fn is_open(&self) -> bool { + self.exit_cell_count.is_none() + } + + /// A description of the stack of currently-open scopes. + pub fn open_stack(&self) -> String { + let mut stack = Vec::new(); + self.open_stack_helper(&mut stack); + stack.join(" > ") + } + + fn open_stack_helper(&self, stack: &mut Vec) { + if self.is_open() { + stack.push(self.name.clone()); + if let Some(last_child) = self.children.last() { + last_child.open_stack_helper(stack); + } + } + } + + pub fn push(&mut self, ctx: &str, mut level: tracing::Level, current_cell_count: usize) { + assert!(self.is_open()); + + // We don't want a scope's log level to be stronger than that of its parent. + level = level.max(self.level); + + if let Some(last_child) = self.children.last_mut() { + if last_child.is_open() { + last_child.push(ctx, level, current_cell_count); + return; + } + } + + self.children.push(ContextTree { + name: ctx.to_string(), + level, + enter_cell_count: current_cell_count, + exit_cell_count: None, + children: vec![], + }) + } + + /// Close the deepest open context from this tree. + pub fn pop(&mut self, current_cell_count: usize) { + assert!(self.is_open()); + + if let Some(last_child) = self.children.last_mut() { + if last_child.is_open() { + last_child.pop(current_cell_count); + return; + } + } + + self.exit_cell_count = Some(current_cell_count); + } + + fn cell_count_delta(&self, current_cell_count: usize) -> usize { + self.exit_cell_count.unwrap_or(current_cell_count) - self.enter_cell_count + } + + /// Filter out children with a low cell count. + pub fn filter(&self, current_cell_count: usize, min_delta: usize) -> Self { + Self { + name: self.name.clone(), + level: self.level, + enter_cell_count: self.enter_cell_count, + exit_cell_count: self.exit_cell_count, + children: self + .children + .iter() + .filter(|c| c.cell_count_delta(current_cell_count) >= min_delta) + .map(|c| c.filter(current_cell_count, min_delta)) + .collect(), + } + } + + pub fn print(&self, current_cell_count: usize) { + println!(); + self.print_helper(current_cell_count, 0); + } + + fn print_helper(&self, current_cell_count: usize, depth: usize) { + let prefix = "| ".repeat(depth); + println!( + "{}{} cells for {}", + prefix, + self.cell_count_delta(current_cell_count), + self.name + ); + for child in &self.children { + child.print_helper(current_cell_count, depth + 1); + } + } + + /// Write folded stack format (for inferno flamegraph input). + pub fn write(&self, buffer: &mut impl Write, current_cell_count: usize) { + self.write_helper(buffer, current_cell_count, ""); + } + + fn write_helper(&self, buffer: &mut impl Write, current_cell_count: usize, prefix: &str) { + let full_name = match (prefix.is_empty(), self.name.as_str()) { + (true, "root") => String::new(), + (true, _) => self.name.clone(), + (false, _) => format!("{};{}", prefix, self.name), + }; + + let mut count = self.cell_count_delta(current_cell_count); + for child in &self.children { + child.write_helper(buffer, current_cell_count, full_name.as_str()); + count -= child.cell_count_delta(current_cell_count); + } + if !full_name.is_empty() && count > 0 { + writeln!(buffer, "{} {}", full_name, count).expect("Failed to write to buffer"); + } + } + + pub fn write_flamegraph( + &self, + svg_buffer: &mut impl Write, + title: &str, + current_cell_count: usize, + reverse: bool, + ) { + let mut buffer = Vec::new(); + self.write(&mut buffer, current_cell_count); + let trace = std::str::from_utf8(&buffer).expect("Buffer is not valid UTF-8"); + + let mut options = Options::default(); + options.title = title.to_string(); + options.count_name = "cells".to_string(); + options.deterministic = true; + + if reverse { + options.direction = Direction::Inverted; + options.reverse_stack_order = true; + } + + flamegraph::from_lines(&mut options, trace.lines(), svg_buffer) + .expect("Failed to write flamegraph"); + } +} diff --git a/patches/openvm-static-verifier/src/field/baby_bear/base.rs b/patches/openvm-static-verifier/src/field/baby_bear/base.rs new file mode 100644 index 00000000..a99274a9 --- /dev/null +++ b/patches/openvm-static-verifier/src/field/baby_bear/base.rs @@ -0,0 +1,596 @@ +use std::{cell::RefCell, collections::HashMap, sync::Arc}; + +use halo2_base::{ + gates::{GateChip, GateInstructions, RangeChip, RangeInstructions}, + halo2_proofs::{ + arithmetic::Field as _, + halo2curves::{bn256::Fr, ff::PrimeField as _}, + }, + safe_types::SafeBool, + utils::{bigint_to_fe, biguint_to_fe, bit_length, fe_to_bigint, modulus, BigPrimeField}, + AssignedValue, Context, QuantumCell, +}; +use itertools::Itertools; +use num_bigint::{BigInt, BigUint}; +use num_integer::Integer; +use openvm_stark_sdk::{ + openvm_stark_backend::p3_field::{Field, PrimeCharacteristicRing, PrimeField32, PrimeField64}, + p3_baby_bear::BabyBear, +}; + +use super::BABY_BEAR_MODULUS_U64; +use crate::utils::{guarded_debug_assert, guarded_debug_assert_eq}; + +pub(crate) const BABYBEAR_MAX_BITS: usize = 31; +// bits reserved so that if we do lazy range checking, we still have a valid result +// the first reserved bit is so that we can represent negative numbers +// the second is to accommodate lazy range checking +const RESERVED_HIGH_BITS: usize = 2; + +#[derive(Copy, Clone, Debug)] +pub struct BabyBearWire { + /// Logically `value` is a signed integer represented as `Bn254`. + /// Invariants: + /// - `|value|` never overflows `Bn254` + /// - `|value| < 2^max_bits` and `max_bits <= Fr::CAPACITY - RESERVED_HIGH_BITS` + /// + /// Basically `value` could do arithmetic operations without extra constraints as long as the + /// result doesn't overflow `Bn254`. And it's easy to track `max_bits` of the result. + pub value: AssignedValue, + /// The value is guaranteed to be less than 2^max_bits. + pub max_bits: usize, +} + +/// A BabyBear wire constrained to its canonical representative in `[0, p)`. +/// +/// This type marks values that are safe to absorb into BabyBear-domain transcript +/// and hash inputs. Arithmetic may still use the underlying `BabyBearWire`; converting +/// via `BabyBearWire::from` only drops this type-level evidence and does not add or +/// remove constraints. +#[derive(Copy, Clone, Debug)] +pub struct ReducedBabyBearWire(BabyBearWire); + +impl ReducedBabyBearWire { + pub fn value(&self) -> AssignedValue { + self.0.value + } +} + +impl From for BabyBearWire { + /// Drops the canonicality evidence and returns the underlying arithmetic wire. + fn from(wire: ReducedBabyBearWire) -> Self { + wire.0 + } +} + +impl From<&ReducedBabyBearWire> for BabyBearWire { + fn from(wire: &ReducedBabyBearWire) -> Self { + (*wire).into() + } +} + +impl BabyBearWire { + pub fn to_baby_bear(&self) -> BabyBear { + let mut b_int = fe_to_bigint(self.value.value()) % BabyBear::ORDER_U32; + if b_int < BigInt::from(0) { + b_int += BabyBear::ORDER_U32; + } + BabyBear::from_u32(b_int.try_into().unwrap()) + } + + pub fn as_u64(&self) -> u64 { + PrimeField64::as_canonical_u64(&self.to_baby_bear()) + } +} + +#[derive(Clone, Debug)] +pub struct BabyBearChip { + pub range: Arc>, + /// Cache for loaded constants, keyed by canonical u64 value. + const_cache: RefCell>, +} + +impl BabyBearChip { + pub fn new(range_chip: Arc>) -> Self { + BabyBearChip { + range: range_chip, + const_cache: RefCell::new(HashMap::new()), + } + } + + pub fn gate(&self) -> &GateChip { + self.range.gate() + } + + pub fn range(&self) -> &RangeChip { + &self.range + } + + /// Loads a BabyBear witness and constrains only that the assigned advice cell + /// fits in 31 bits. + /// + /// The Rust input is canonicalized for the honest witness assignment, but the + /// circuit does not prove the advice cell is `< p`. Use `load_reduced_witness` + /// for values that will be absorbed into transcripts or hashes. + pub fn load_witness(&self, ctx: &mut Context, value: BabyBear) -> BabyBearWire { + let value = ctx.load_witness(Fr::from(PrimeField64::as_canonical_u64(&value))); + self.range.range_check(ctx, value, BABYBEAR_MAX_BITS); + BabyBearWire { + value, + max_bits: BABYBEAR_MAX_BITS, + } + } + + /// Loads a witness and constrains it to the canonical BabyBear range `[0, p)`. + pub fn load_reduced_witness( + &self, + ctx: &mut Context, + value: BabyBear, + ) -> ReducedBabyBearWire { + let value = ctx.load_witness(Fr::from(PrimeField64::as_canonical_u64(&value))); + self.range + .check_less_than_safe(ctx, value, BABY_BEAR_MODULUS_U64); + ReducedBabyBearWire(BabyBearWire { + value, + max_bits: BABYBEAR_MAX_BITS, + }) + } + + pub fn load_constant(&self, ctx: &mut Context, value: BabyBear) -> BabyBearWire { + let key = value.as_canonical_u64(); + if let Some(&cached) = self.const_cache.borrow().get(&key) { + return cached; + } + let max_bits = bit_length(key); + let assigned = if value == BabyBear::ZERO { + ctx.load_zero() + } else { + ctx.load_constant(Fr::from(key)) + }; + let wire = BabyBearWire { + value: assigned, + max_bits, + }; + self.const_cache.borrow_mut().insert(key, wire); + wire + } + + /// Loads a canonical BabyBear constant and returns it with reduced type evidence. + pub fn load_reduced_constant( + &self, + ctx: &mut Context, + value: BabyBear, + ) -> ReducedBabyBearWire { + // Constants are canonical by construction. + ReducedBabyBearWire(self.load_constant(ctx, value)) + } + + pub fn reduce(&self, ctx: &mut Context, a: BabyBearWire) -> BabyBearWire { + assert!(a.max_bits <= Fr::CAPACITY as usize - RESERVED_HIGH_BITS); + guarded_debug_assert!(fe_to_bigint(a.value.value()).bits() as usize <= a.max_bits); + let (_, r) = signed_div_mod(&self.range, ctx, a.value, a.max_bits); + let r = BabyBearWire { + value: r, + max_bits: BABYBEAR_MAX_BITS, + }; + guarded_debug_assert_eq!(a.to_baby_bear(), r.to_baby_bear()); + r + } + + /// Reduce max_bits if possible. This function doesn't guarantee that the actual value is within + /// BabyBear. + pub fn reduce_max_bits(&self, ctx: &mut Context, a: BabyBearWire) -> BabyBearWire { + if a.max_bits > BABYBEAR_MAX_BITS { + self.reduce(ctx, a) + } else { + a + } + } + + pub fn add( + &self, + ctx: &mut Context, + mut a: BabyBearWire, + mut b: BabyBearWire, + ) -> BabyBearWire { + if a.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + a = self.reduce(ctx, a); + } + if b.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + b = self.reduce(ctx, b); + } + let value = self.gate().add(ctx, a.value, b.value); + let max_bits = a.max_bits.max(b.max_bits) + 1; + let c = BabyBearWire { value, max_bits }; + guarded_debug_assert_eq!(c.to_baby_bear(), a.to_baby_bear() + b.to_baby_bear()); + c + } + + pub fn neg(&self, ctx: &mut Context, a: BabyBearWire) -> BabyBearWire { + let value = self.gate().neg(ctx, a.value); + let b = BabyBearWire { + value, + max_bits: a.max_bits, + }; + guarded_debug_assert_eq!(b.to_baby_bear(), -a.to_baby_bear()); + b + } + + pub fn sub( + &self, + ctx: &mut Context, + mut a: BabyBearWire, + mut b: BabyBearWire, + ) -> BabyBearWire { + #[cfg(debug_assertions)] + let expected = a.to_baby_bear() - b.to_baby_bear(); + if a.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + a = self.reduce(ctx, a); + } + if b.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + b = self.reduce(ctx, b); + } + let value = self.gate().sub(ctx, a.value, b.value); + let max_bits = a.max_bits.max(b.max_bits) + 1; + let c = BabyBearWire { value, max_bits }; + guarded_debug_assert_eq!(c.to_baby_bear(), expected); + c + } + + pub fn mul( + &self, + ctx: &mut Context, + mut a: BabyBearWire, + mut b: BabyBearWire, + ) -> BabyBearWire { + if a.max_bits < b.max_bits { + std::mem::swap(&mut a, &mut b); + } + if a.max_bits + b.max_bits > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + a = self.reduce(ctx, a); + if a.max_bits + b.max_bits > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + b = self.reduce(ctx, b); + } + } + let value = self.gate().mul(ctx, a.value, b.value); + let max_bits = a.max_bits + b.max_bits; + + let c = BabyBearWire { value, max_bits }; + guarded_debug_assert_eq!(c.to_baby_bear(), a.to_baby_bear() * b.to_baby_bear()); + c + } + + pub fn mul_add( + &self, + ctx: &mut Context, + mut a: BabyBearWire, + mut b: BabyBearWire, + mut c: BabyBearWire, + ) -> BabyBearWire { + if a.max_bits < b.max_bits { + std::mem::swap(&mut a, &mut b); + } + if a.max_bits + b.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + a = self.reduce(ctx, a); + if a.max_bits + b.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + b = self.reduce(ctx, b); + } + } + if c.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + c = self.reduce(ctx, c) + } + let value = self.gate().mul_add(ctx, a.value, b.value, c.value); + let max_bits = c.max_bits.max(a.max_bits + b.max_bits) + 1; + + let d = BabyBearWire { value, max_bits }; + guarded_debug_assert_eq!( + d.to_baby_bear(), + a.to_baby_bear() * b.to_baby_bear() + c.to_baby_bear() + ); + d + } + + pub fn div( + &self, + ctx: &mut Context, + mut a: BabyBearWire, + mut b: BabyBearWire, + ) -> BabyBearWire { + let b_val = b.to_baby_bear(); + let b_inv_val = b_val.try_inverse().unwrap(); + // Constrain b is non-zero by checking b * b_inv == 1 + let b_inv = self.load_witness(ctx, b_inv_val); + let one = self.load_constant(ctx, BabyBear::ONE); + let inv_prod = self.mul(ctx, b, b_inv); + self.assert_equal(ctx, inv_prod, one); + + // Constrain a = b * c (mod p) + let mut c = self.load_witness(ctx, a.to_baby_bear() * b_inv_val); + if a.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + a = self.reduce(ctx, a); + } + if b.max_bits + c.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + b = self.reduce(ctx, b); + } + if b.max_bits + c.max_bits + 1 > Fr::CAPACITY as usize - RESERVED_HIGH_BITS { + c = self.reduce(ctx, c); + } + let diff = self.gate().sub_mul(ctx, a.value, b.value, c.value); + let max_bits = a.max_bits.max(b.max_bits + c.max_bits) + 1; + self.assert_zero( + ctx, + BabyBearWire { + value: diff, + max_bits, + }, + ); + guarded_debug_assert_eq!(c.to_baby_bear(), a.to_baby_bear() / b.to_baby_bear()); + c + } + + // This inner product function will be used exclusively for optimizing extension element + // multiplication. + pub(super) fn special_inner_product( + &self, + ctx: &mut Context, + a: &mut [BabyBearWire], + b: &mut [BabyBearWire], + s: usize, + ) -> BabyBearWire { + assert!(a.len() == b.len()); + assert!(a.len() == 4); + let mut max_bits = 0; + let lb = s.saturating_sub(3); + let ub = 4.min(s + 1); + let range = lb..ub; + let other_range = (s + 1 - ub)..(s + 1 - lb); + let len = if s < 3 { s + 1 } else { 7 - s }; + for (i, (c, d)) in a[range.clone()] + .iter_mut() + .zip(b[other_range.clone()].iter_mut().rev()) + .enumerate() + { + if c.max_bits + d.max_bits > Fr::CAPACITY as usize - RESERVED_HIGH_BITS - len + i { + if c.max_bits >= d.max_bits { + *c = self.reduce(ctx, *c); + if c.max_bits + d.max_bits + > Fr::CAPACITY as usize - RESERVED_HIGH_BITS - len + i + { + *d = self.reduce(ctx, *d); + } + } else { + *d = self.reduce(ctx, *d); + if c.max_bits + d.max_bits + > Fr::CAPACITY as usize - RESERVED_HIGH_BITS - len + i + { + *c = self.reduce(ctx, *c); + } + } + } + if i == 0 { + max_bits = c.max_bits + d.max_bits; + } else { + max_bits = max_bits.max(c.max_bits + d.max_bits) + 1 + } + } + let a_raw = a[range] + .iter() + .map(|a| QuantumCell::Existing(a.value)) + .collect_vec(); + let b_raw = b[other_range] + .iter() + .rev() + .map(|b| QuantumCell::Existing(b.value)) + .collect_vec(); + let prod = self.gate().inner_product(ctx, a_raw, b_raw); + BabyBearWire { + value: prod, + max_bits, + } + } + + pub fn select( + &self, + ctx: &mut Context, + cond: SafeBool, + a: BabyBearWire, + b: BabyBearWire, + ) -> BabyBearWire { + let value = self.gate().select(ctx, a.value, b.value, *cond.as_ref()); + let max_bits = a.max_bits.max(b.max_bits); + BabyBearWire { value, max_bits } + } + + pub fn assert_zero(&self, ctx: &mut Context, a: BabyBearWire) { + guarded_debug_assert_eq!(a.to_baby_bear(), BabyBear::ZERO); + assert!(a.max_bits <= Fr::CAPACITY as usize - RESERVED_HIGH_BITS); + let a_num_bits = a.max_bits; + let b: BigUint = BabyBear::ORDER_U32.into(); + let a_val = fe_to_bigint(a.value.value()); + assert!(a_val.bits() <= a_num_bits as u64); + // The honest input is congruent to zero modulo the BabyBear prime, so + // Euclidean division by `b` has exact remainder zero. + let (div, _) = a_val.div_mod_floor(&b.clone().into()); + let div = bigint_to_fe(&div); + ctx.assign_region( + [ + QuantumCell::Constant(Fr::ZERO), + QuantumCell::Constant(biguint_to_fe(&b)), + QuantumCell::Witness(div), + a.value.into(), + ], + [0], + ); + let div = ctx.get(-2); + // Constrain the exact quotient to the range implied by `|a| < 2^a_num_bits`. + let bound = (BigUint::from(1u32) << (a_num_bits as u32)) / &b; + let shifted_div = + self.range + .gate() + .add(ctx, div, QuantumCell::Constant(biguint_to_fe(&bound))); + guarded_debug_assert!(*shifted_div.value() < biguint_to_fe(&(&bound * 2u32 + 1u32))); + self.range + .range_check(ctx, shifted_div, (bound * 2u32 + 1u32).bits() as usize); + } + + pub fn assert_equal(&self, ctx: &mut Context, a: BabyBearWire, b: BabyBearWire) { + guarded_debug_assert_eq!(a.to_baby_bear(), b.to_baby_bear()); + let diff = self.sub(ctx, a, b); + self.assert_zero(ctx, diff); + } + + pub fn zero(&self, ctx: &mut Context) -> BabyBearWire { + self.load_constant(ctx, BabyBear::ZERO) + } + + pub fn one(&self, ctx: &mut Context) -> BabyBearWire { + self.load_constant(ctx, BabyBear::ONE) + } + + pub fn mul_const(&self, ctx: &mut Context, a: BabyBearWire, c: BabyBear) -> BabyBearWire { + let c_wire = self.load_constant(ctx, c); + self.mul(ctx, a, c_wire) + } + + pub fn square(&self, ctx: &mut Context, a: BabyBearWire) -> BabyBearWire { + self.mul(ctx, a, a) + } + + pub fn pow_power_of_two( + &self, + ctx: &mut Context, + a: BabyBearWire, + n: usize, + ) -> BabyBearWire { + let mut result = a; + for _ in 0..n { + result = self.square(ctx, result); + } + result + } +} + +/// Constrains and returns `(div, rem)` encoding integers `D` and `R` such that +/// `A = BabyBear::ORDER_U32 * D + R` with `0 <= R < BabyBear::ORDER_U32`, where +/// `A = fe_to_bigint(a)` is the canonical signed representative of `a` in +/// `(-p/2, p/2]` and `p = F::MODULUS`. +/// +/// The returned `div` cell encodes the possibly negative integer `D` modulo +/// `p`; the returned `rem` cell encodes the canonical nonnegative integer `R`. +/// +/// # Arguments +/// +/// * `a` - the [`QuantumCell`] value to divide. +/// * `a_num_bits` - a bound such that `|A| < 2^a_num_bits`. +/// +/// # Preconditions +/// +/// This function does not itself range-check `a`. The caller must ensure, +/// either by prior constraints or by construction, that the canonical signed +/// representative `A = fe_to_bigint(a)` satisfies `|A| < 2^a_num_bits`. +fn signed_div_mod( + range: &RangeChip, + ctx: &mut Context, + a: impl Into>, + a_num_bits: usize, +) -> (AssignedValue, AssignedValue) +where + F: BigPrimeField, +{ + assert!(a_num_bits <= F::CAPACITY as usize - RESERVED_HIGH_BITS); + // Proof sketch: + // + // Let `b = BabyBear::ORDER_U32`, `p = F::MODULUS`, and let + // `A = fe_to_bigint(a)` be the canonical signed representative of `a`. + // Assume `|A| < 2^a_num_bits`. + // + // The intended witnesses are the Euclidean quotient and remainder: + // + // div = floor(A / b), rem = A mod b, 0 <= rem < b. + // + // We enforce: + // + // (1) rem + b * div = a over F + // (2) 0 <= rem < b + // (3) 0 <= div + bound < 2^k + // + // where + // + // bound = ceil((2^a_num_bits - 1) / b) + // k = bits(2 * bound + 1). + // + // Completeness is immediate: since `|A| <= 2^a_num_bits - 1`, the honest + // quotient satisfies `|div| <= bound`, so `div + bound` lies in + // `[0, 2 * bound]` and passes the `k`-bit range check. + // + // For soundness, note that the `k`-bit check is slightly looser than + // `div + bound <= 2 * bound`. For any satisfying assignment, let `S` be the + // canonical integer value of `div + bound`, so `0 <= S < 2^k`, and set + // `D = S - bound`. Since `2^k <= 4 * bound + 2`, we have + // + // -bound <= D <= 3 * bound + 1. + // + // Thus any two satisfying assignments `(D, R)` and `(D', R')` obey + // + // |D - D'| <= 4 * bound + 1, + // |R - R'| < b. + // + // Both assignments satisfy: + // + // R + b * D = a mod p + // R' + b * D' = a mod p + // + // Subtracting the second congruence from the first gives + // + // (D - D') * b - (R' - R) = 0 mod p. + // + // Equivalently, this integer is some multiple of `p`: + // + // (D - D') * b - (R' - R) = m * p. + // + // Its magnitude is bounded by + // + // |(D - D') * b - (R' - R)| < (4 * bound + 2) * b. + // + // The runtime assertion + // + // assert!((4 * bound + 2) * b <= p) + // + // ensures this magnitude is strictly less than `p`. The only multiple of `p` + // with magnitude less than `p` is zero, so `m = 0`. Therefore + // + // (D - D') * b = R' - R. + // + // The left side is divisible by `b`, while the right side has magnitude `< b`. + // Hence both sides are zero, so `D = D'` and `R = R'`. + let a = a.into(); + let b = BigUint::from(BabyBear::ORDER_U32); + let a_val = fe_to_bigint(a.value()); + assert!(a_val.bits() <= a_num_bits as u64); + let (div, rem) = a_val.div_mod_floor(&b.clone().into()); + let [div, rem] = [div, rem].map(|v| bigint_to_fe(&v)); + ctx.assign_region( + [ + QuantumCell::Witness(rem), + QuantumCell::Constant(biguint_to_fe(&b)), + QuantumCell::Witness(div), + a, + ], + [0], + ); + let rem = ctx.get(-4); + let div = ctx.get(-2); + // `bound = ceil((2^a_num_bits - 1) / b)`; the bit-length range check below admits + // `div in [-bound, 3*bound+1]`, and the assertion enforces the no-wrap headroom + // `(4 * bound + 2) * b <= p`. See the proof above for both. + let bound = ((BigUint::from(1u32) << a_num_bits) - 1u32).div_ceil(&b); + assert!((&bound * 4u32 + 2u32) * &b <= modulus::()); + let shifted_div = range + .gate() + .add(ctx, div, QuantumCell::Constant(biguint_to_fe(&bound))); + guarded_debug_assert!(*shifted_div.value() < biguint_to_fe(&(&bound * 2u32 + 1u32))); + range.range_check(ctx, shifted_div, (bound * 2u32 + 1u32).bits() as usize); + guarded_debug_assert!(*rem.value() < biguint_to_fe(&b)); + range.check_big_less_than_safe(ctx, rem, b); + (div, rem) +} diff --git a/patches/openvm-static-verifier/src/field/baby_bear/extension.rs b/patches/openvm-static-verifier/src/field/baby_bear/extension.rs new file mode 100644 index 00000000..9abe3f66 --- /dev/null +++ b/patches/openvm-static-verifier/src/field/baby_bear/extension.rs @@ -0,0 +1,358 @@ +use core::array; +#[cfg(test)] +use std::{cell::RefCell, vec::Vec}; + +#[cfg(test)] +use halo2_base::AssignedValue; +use halo2_base::{ + gates::range::RangeChip, halo2_proofs::halo2curves::bn256::Fr, safe_types::SafeBool, Context, +}; +use itertools::Itertools; +#[cfg(test)] +use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField64; +use openvm_stark_sdk::{ + openvm_stark_backend::p3_field::{ + extension::{BinomialExtensionField, BinomiallyExtendable}, + BasedVectorSpace, Field, PrimeCharacteristicRing, + }, + p3_baby_bear::BabyBear, +}; + +use crate::{ + field::baby_bear::{BabyBearChip, BabyBearWire, ReducedBabyBearWire}, + utils::guarded_debug_assert_eq, +}; + +#[cfg(test)] +pub(crate) struct RecordedExtBaseConst { + pub constant: u64, + pub cell: AssignedValue, +} + +#[cfg(test)] +thread_local! { + static RECORDED_EXT_BASE_CONSTS: RefCell> = const { RefCell::new(Vec::new()) }; +} + +#[cfg(test)] +pub(crate) fn clear_recorded_ext_base_consts() { + RECORDED_EXT_BASE_CONSTS.with(|records| records.borrow_mut().clear()); +} + +#[cfg(test)] +pub(crate) fn take_recorded_ext_base_consts() -> Vec { + RECORDED_EXT_BASE_CONSTS.with(|records| records.borrow_mut().drain(..).collect()) +} + +// irred poly is x^4 - 11 +#[derive(Clone)] +pub struct BabyBearExt4Chip { + pub base: BabyBearChip, +} + +#[derive(Copy, Clone, Debug)] +pub struct BabyBearExt4Wire(pub [BabyBearWire; 4]); + +/// An extension-field wire whose BabyBear basis coefficients are all reduced. +/// +/// This is the extension-field analogue of `ReducedBabyBearWire`: it is safe for +/// transcript/hash absorption coefficient-by-coefficient. Converting via +/// `BabyBearExt4Wire::from` drops that evidence when the value is used by arithmetic +/// helpers. +#[derive(Copy, Clone, Debug)] +pub struct ReducedBabyBearExt4Wire([ReducedBabyBearWire; 4]); +pub type BabyBearExt4 = BinomialExtensionField; + +impl BabyBearExt4Wire { + pub fn to_extension_field(&self) -> BabyBearExt4 { + BabyBearExt4::from_basis_coefficients_fn(|i| self.0[i].to_baby_bear()) + } +} + +impl ReducedBabyBearExt4Wire { + pub fn coeffs(&self) -> &[ReducedBabyBearWire; 4] { + &self.0 + } +} + +impl From for BabyBearExt4Wire { + /// Drops the canonicality evidence and returns the underlying arithmetic wire. + fn from(wire: ReducedBabyBearExt4Wire) -> Self { + BabyBearExt4Wire(wire.0.map(BabyBearWire::from)) + } +} + +impl From<&ReducedBabyBearExt4Wire> for BabyBearExt4Wire { + fn from(wire: &ReducedBabyBearExt4Wire) -> Self { + (*wire).into() + } +} + +impl BabyBearExt4Chip { + pub fn new(base_chip: BabyBearChip) -> Self { + BabyBearExt4Chip { base: base_chip } + } + + /// Loads each BabyBear coefficient and constrains only that its assigned + /// advice cell fits in 31 bits. + /// + /// The Rust input is canonicalized for the honest witness assignment, but the + /// circuit does not prove each advice cell is `< p`. Use + /// `load_reduced_witness` for transcript/hash inputs. + pub fn load_witness(&self, ctx: &mut Context, value: BabyBearExt4) -> BabyBearExt4Wire { + let coeffs = value.as_basis_coefficients_slice(); + BabyBearExt4Wire(array::from_fn(|i| self.base.load_witness(ctx, coeffs[i]))) + } + + /// Loads each coefficient and constrains it to the canonical BabyBear range. + pub fn load_reduced_witness( + &self, + ctx: &mut Context, + value: BabyBearExt4, + ) -> ReducedBabyBearExt4Wire { + let coeffs = value.as_basis_coefficients_slice(); + ReducedBabyBearExt4Wire(array::from_fn(|i| { + self.base.load_reduced_witness(ctx, coeffs[i]) + })) + } + + /// Loads canonical BabyBear constants for each coefficient and returns them + /// with reduced type evidence. + pub fn load_reduced_constant( + &self, + ctx: &mut Context, + value: BabyBearExt4, + ) -> ReducedBabyBearExt4Wire { + let coeffs = value.as_basis_coefficients_slice(); + // Constants are canonical by construction. + ReducedBabyBearExt4Wire(array::from_fn(|i| { + self.base.load_reduced_constant(ctx, coeffs[i]) + })) + } + pub fn load_constant(&self, ctx: &mut Context, value: BabyBearExt4) -> BabyBearExt4Wire { + let coeffs = value.as_basis_coefficients_slice(); + BabyBearExt4Wire(array::from_fn(|i| self.base.load_constant(ctx, coeffs[i]))) + } + pub fn add( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + b: BabyBearExt4Wire, + ) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.iter() + .zip(b.0.iter()) + .map(|(a, b)| self.base.add(ctx, *a, *b)) + .collect_vec() + .try_into() + .unwrap(), + ) + } + + pub fn neg(&self, ctx: &mut Context, a: BabyBearExt4Wire) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.iter() + .map(|x| self.base.neg(ctx, *x)) + .collect_vec() + .try_into() + .unwrap(), + ) + } + + pub fn sub( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + b: BabyBearExt4Wire, + ) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.iter() + .zip(b.0.iter()) + .map(|(a, b)| self.base.sub(ctx, *a, *b)) + .collect_vec() + .try_into() + .unwrap(), + ) + } + + pub fn scalar_mul( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + b: BabyBearWire, + ) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.iter() + .map(|x| self.base.mul(ctx, *x, b)) + .collect_vec() + .try_into() + .unwrap(), + ) + } + + /// Fused `a * b + c` where `b` is a base-field scalar. + /// Uses `mul_add` gates to save cells vs separate `scalar_mul` + `add`. + pub fn scalar_mul_add( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + b: BabyBearWire, + c: BabyBearExt4Wire, + ) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.iter() + .zip(c.0.iter()) + .map(|(ai, ci)| self.base.mul_add(ctx, *ai, b, *ci)) + .collect_vec() + .try_into() + .unwrap(), + ) + } + + pub fn select( + &self, + ctx: &mut Context, + cond: SafeBool, + a: BabyBearExt4Wire, + b: BabyBearExt4Wire, + ) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.iter() + .zip(b.0.iter()) + .map(|(a, b)| self.base.select(ctx, cond, *a, *b)) + .collect_vec() + .try_into() + .unwrap(), + ) + } + + pub fn assert_zero(&self, ctx: &mut Context, a: BabyBearExt4Wire) { + for x in a.0.iter() { + self.base.assert_zero(ctx, *x); + } + } + + pub fn assert_equal(&self, ctx: &mut Context, a: BabyBearExt4Wire, b: BabyBearExt4Wire) { + for (a, b) in a.0.iter().zip(b.0.iter()) { + self.base.assert_equal(ctx, *a, *b); + } + } + + pub fn mul( + &self, + ctx: &mut Context, + mut a: BabyBearExt4Wire, + mut b: BabyBearExt4Wire, + ) -> BabyBearExt4Wire { + let mut coeffs = Vec::with_capacity(7); + for s in 0..7 { + coeffs.push(self.base.special_inner_product(ctx, &mut a.0, &mut b.0, s)); + } + let w = self + .base + .load_constant(ctx, >::W); + for i in 4..7 { + coeffs[i - 4] = self.base.mul_add(ctx, coeffs[i], w, coeffs[i - 4]); + } + coeffs.truncate(4); + let c = BabyBearExt4Wire(coeffs.try_into().unwrap()); + guarded_debug_assert_eq!( + c.to_extension_field(), + a.to_extension_field() * b.to_extension_field() + ); + c + } + + pub fn div( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + b: BabyBearExt4Wire, + ) -> BabyBearExt4Wire { + let b_val = b.to_extension_field(); + let b_inv_val = b_val.try_inverse().unwrap(); + // Constrain b is non-zero by checking b * b_inv == 1 + let b_inv = self.load_witness(ctx, b_inv_val); + let one = self.load_constant(ctx, BinomialExtensionField::::ONE); + let inv_prod = self.mul(ctx, b, b_inv); + self.assert_equal(ctx, inv_prod, one); + + // Constrain a = b * c (mod p) + let c = self.load_witness(ctx, a.to_extension_field() * b_inv_val); + let prod = self.mul(ctx, b, c); + self.assert_equal(ctx, a, prod); + + guarded_debug_assert_eq!( + c.to_extension_field(), + a.to_extension_field() / b.to_extension_field() + ); + c + } + + pub fn reduce_max_bits(&self, ctx: &mut Context, a: BabyBearExt4Wire) -> BabyBearExt4Wire { + BabyBearExt4Wire( + a.0.into_iter() + .map(|x| self.base.reduce_max_bits(ctx, x)) + .collect::>() + .try_into() + .unwrap(), + ) + } + + pub fn base(&self) -> &BabyBearChip { + &self.base + } + + pub fn range(&self) -> &RangeChip { + self.base.range() + } + + pub fn zero(&self, ctx: &mut Context) -> BabyBearExt4Wire { + self.from_base_const(ctx, BabyBear::ZERO) + } + + pub fn from_base_const(&self, ctx: &mut Context, value: BabyBear) -> BabyBearExt4Wire { + let base_val = self.base.load_constant(ctx, value); + #[cfg(test)] + RECORDED_EXT_BASE_CONSTS.with(|records| { + records.borrow_mut().push(RecordedExtBaseConst { + constant: value.as_canonical_u64(), + cell: base_val.value, + }); + }); + let z = self.base.load_constant(ctx, BabyBear::ZERO); + BabyBearExt4Wire([base_val, z, z, z]) + } + + pub fn from_base_var(&self, ctx: &mut Context, value: BabyBearWire) -> BabyBearExt4Wire { + let z = self.base.load_constant(ctx, BabyBear::ZERO); + BabyBearExt4Wire([value, z, z, z]) + } + + pub fn mul_base_const( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + c: BabyBear, + ) -> BabyBearExt4Wire { + let c_wire = self.base.load_constant(ctx, c); + self.scalar_mul(ctx, a, c_wire) + } + + pub fn square(&self, ctx: &mut Context, a: BabyBearExt4Wire) -> BabyBearExt4Wire { + self.mul(ctx, a, a) + } + + pub fn pow_power_of_two( + &self, + ctx: &mut Context, + a: BabyBearExt4Wire, + n: usize, + ) -> BabyBearExt4Wire { + let mut result = a; + for _ in 0..n { + result = self.square(ctx, result); + } + result + } +} diff --git a/patches/openvm-static-verifier/src/field/baby_bear/mod.rs b/patches/openvm-static-verifier/src/field/baby_bear/mod.rs new file mode 100644 index 00000000..2e180e0f --- /dev/null +++ b/patches/openvm-static-verifier/src/field/baby_bear/mod.rs @@ -0,0 +1,16 @@ +mod base; +mod extension; + +pub use base::*; +pub use extension::*; + +pub(crate) const BABY_BEAR_MODULUS_U64: u64 = 0x78000001; // BabyBear prime: 2013265921 +pub(crate) const BABY_BEAR_EXT_DEGREE: usize = 4; +pub(crate) const BABY_BEAR_BITS: usize = BABYBEAR_MAX_BITS; + +pub type BabyBearExtChip = BabyBearExt4Chip; +pub type BabyBearExtWire = BabyBearExt4Wire; +pub type ReducedBabyBearExtWire = ReducedBabyBearExt4Wire; + +#[cfg(test)] +mod tests; diff --git a/patches/openvm-static-verifier/src/field/baby_bear/tests.rs b/patches/openvm-static-verifier/src/field/baby_bear/tests.rs new file mode 100644 index 00000000..8700826a --- /dev/null +++ b/patches/openvm-static-verifier/src/field/baby_bear/tests.rs @@ -0,0 +1,203 @@ +use std::sync::Arc; + +use halo2_base::{ + gates::{ + circuit::{builder::BaseCircuitBuilder, CircuitBuilderStage}, + GateInstructions, RangeInstructions, + }, + halo2_proofs::dev::MockProver, +}; +use openvm_stark_sdk::openvm_stark_backend::p3_field::{ + BasedVectorSpace, PrimeCharacteristicRing, PrimeField64, +}; + +use super::*; +use crate::{ + config::{STATIC_VERIFIER_LOOKUP_ADVICE_COLS, STATIC_VERIFIER_NUM_ADVICE_COLS}, + Fr, RootEF, RootF, +}; + +fn run_mock(build: impl FnOnce(&mut BaseCircuitBuilder)) { + let mut builder = BaseCircuitBuilder::from_stage(CircuitBuilderStage::Mock) + .use_k(12) + .use_lookup_bits(11) + .use_instance_columns(1); + build(&mut builder); + + let params = builder.calculate_params(Some(20)); + assert_eq!( + params + .num_advice_per_phase + .first() + .copied() + .unwrap_or_default(), + STATIC_VERIFIER_NUM_ADVICE_COLS + ); + assert_eq!( + params + .num_lookup_advice_per_phase + .first() + .copied() + .unwrap_or_default(), + STATIC_VERIFIER_LOOKUP_ADVICE_COLS + ); + + MockProver::run(12, &builder, vec![vec![]]) + .expect("mock prover should initialize") + .assert_satisfied(); +} + +#[test] +fn baby_bear_base_ops_match_native_mod_arithmetic() { + run_mock(|builder| { + let range = builder.range_chip(); + let chip = BabyBearChip::new(Arc::new(range.clone())); + let ctx = builder.main(0); + let gate = range.gate(); + + let cases = [ + (0u64, 0u64), + (1, 2), + (5, 13), + (BABY_BEAR_MODULUS_U64 - 1, 1), + (BABY_BEAR_MODULUS_U64 - 2, BABY_BEAR_MODULUS_U64 - 3), + ]; + + for (a_u64, b_u64) in cases { + let a = chip.load_witness(ctx, RootF::from_u64(a_u64)); + let b = chip.load_witness(ctx, RootF::from_u64(b_u64)); + + // Reduce results to canonical form before comparing, since the new + // BabyBearChip uses lazy reduction and wire values may be unreduced. + let sum = chip.add(ctx, a, b); + let sum = chip.reduce(ctx, sum); + let diff = chip.sub(ctx, a, b); + let diff = chip.reduce(ctx, diff); + let prod = chip.mul(ctx, a, b); + let prod = chip.reduce(ctx, prod); + let neg = chip.neg(ctx, a); + let neg = chip.reduce(ctx, neg); + let by_const = chip.mul_const(ctx, a, RootF::from_u64(11)); + let by_const = chip.reduce(ctx, by_const); + + let expected_sum = (a_u64 + b_u64) % BABY_BEAR_MODULUS_U64; + let expected_diff = (a_u64 + BABY_BEAR_MODULUS_U64 - b_u64) % BABY_BEAR_MODULUS_U64; + let expected_prod = + ((a_u64 as u128 * b_u64 as u128) % BABY_BEAR_MODULUS_U64 as u128) as u64; + let expected_neg = if a_u64 == 0 { + 0 + } else { + BABY_BEAR_MODULUS_U64 - a_u64 + }; + let expected_by_const = + ((a_u64 as u128 * 11u128) % BABY_BEAR_MODULUS_U64 as u128) as u64; + + gate.assert_is_const(ctx, &sum.value, &Fr::from(expected_sum)); + gate.assert_is_const(ctx, &diff.value, &Fr::from(expected_diff)); + gate.assert_is_const(ctx, &prod.value, &Fr::from(expected_prod)); + gate.assert_is_const(ctx, &neg.value, &Fr::from(expected_neg)); + gate.assert_is_const(ctx, &by_const.value, &Fr::from(expected_by_const)); + } + }); +} + +/// Reducing a negative wire with a tight `max_bits` must succeed. `neg(one)` yields +/// `value == -1`, `max_bits == 1`, so `reduce` drives `signed_div_mod(-1, 1)` whose +/// quotient `div == -1` has magnitude one even though `floor(2^1 / b) == 0`; this +/// exercises the `ceil((2^a_num_bits - 1) / b)` quotient bound. +#[test] +fn reduce_negative_value_with_tight_max_bits() { + run_mock(|builder| { + let range = builder.range_chip(); + let chip = BabyBearChip::new(Arc::new(range.clone())); + let ctx = builder.main(0); + let gate = range.gate(); + + let one = chip.load_constant(ctx, RootF::ONE); + let neg_one = chip.neg(ctx, one); // value == -1, max_bits == 1 + + // `-1` reduces to its canonical representative `p - 1`. + let reduced = chip.reduce(ctx, neg_one); + gate.assert_is_const(ctx, &reduced.value, &Fr::from(BABY_BEAR_MODULUS_U64 - 1)); + }); +} + +#[test] +fn div_reduces_operand_at_max_bits_boundary() { + run_mock(|builder| { + let range = builder.range_chip(); + let chip = BabyBearChip::new(Arc::new(range.clone())); + let ctx = builder.main(0); + let gate = range.gate(); + + // Honest value is 1, but the wire is deliberately tagged as unreduced with + // `max_bits` exactly at the pre-reduction threshold. + const BOUNDARY_MAX_BITS: usize = 251; // Fr::CAPACITY (253) - RESERVED_HIGH_BITS (2) + let a = BabyBearWire { + value: ctx.load_witness(Fr::from(1u64)), + max_bits: BOUNDARY_MAX_BITS, + }; + let b = chip.load_constant(ctx, RootF::ONE); + + // Before the fix this panics in `assert_zero`; after the fix `a` is reduced + // first and the division yields 1. + let c = chip.div(ctx, a, b); + let c = chip.reduce(ctx, c); + gate.assert_is_const(ctx, &c.value, &Fr::from(1u64)); + }); +} + +#[test] +fn baby_bear_ext_mul_matches_native_binomial_extension() { + run_mock(|builder| { + let range = builder.range_chip(); + let base_chip = BabyBearChip::new(Arc::new(range)); + let ext_chip = BabyBearExt4Chip::new(base_chip); + let ctx = builder.main(0); + let gate = ext_chip.base().gate(); + + let lhs_native = RootEF::from_basis_coefficients_fn(|i| RootF::from_u64([3, 5, 7, 11][i])); + let rhs_native = RootEF::from_basis_coefficients_fn(|i| RootF::from_u64([2, 4, 6, 8][i])); + + let lhs = ext_chip.load_witness(ctx, lhs_native); + let rhs = ext_chip.load_witness(ctx, rhs_native); + + let sum = ext_chip.add(ctx, lhs, rhs); + let sum = ext_chip.reduce_max_bits(ctx, sum); + let diff = ext_chip.sub(ctx, lhs, rhs); + let diff = ext_chip.reduce_max_bits(ctx, diff); + let prod = ext_chip.mul(ctx, lhs, rhs); + let prod = ext_chip.reduce_max_bits(ctx, prod); + let sqr = ext_chip.square(ctx, lhs); + let sqr = ext_chip.reduce_max_bits(ctx, sqr); + + let sum_native = lhs_native + rhs_native; + let diff_native = lhs_native - rhs_native; + let prod_native = lhs_native * rhs_native; + let sqr_native = lhs_native * lhs_native; + + let expected_sum = core::array::from_fn::<_, 4, _>(|i| { + >::as_basis_coefficients_slice(&sum_native)[i] + .as_canonical_u64() + }); + let expected_diff = core::array::from_fn::<_, 4, _>(|i| { + >::as_basis_coefficients_slice(&diff_native)[i] + .as_canonical_u64() + }); + let expected_prod = core::array::from_fn::<_, 4, _>(|i| { + >::as_basis_coefficients_slice(&prod_native)[i] + .as_canonical_u64() + }); + let expected_sqr = core::array::from_fn::<_, 4, _>(|i| { + >::as_basis_coefficients_slice(&sqr_native)[i] + .as_canonical_u64() + }); + + for i in 0..BABY_BEAR_EXT_DEGREE { + gate.assert_is_const(ctx, &sum.0[i].value, &Fr::from(expected_sum[i])); + gate.assert_is_const(ctx, &diff.0[i].value, &Fr::from(expected_diff[i])); + gate.assert_is_const(ctx, &prod.0[i].value, &Fr::from(expected_prod[i])); + gate.assert_is_const(ctx, &sqr.0[i].value, &Fr::from(expected_sqr[i])); + } + }); +} diff --git a/patches/openvm-static-verifier/src/field/mod.rs b/patches/openvm-static-verifier/src/field/mod.rs new file mode 100644 index 00000000..1f5fac43 --- /dev/null +++ b/patches/openvm-static-verifier/src/field/mod.rs @@ -0,0 +1 @@ +pub mod baby_bear; diff --git a/patches/openvm-static-verifier/src/hash/mod.rs b/patches/openvm-static-verifier/src/hash/mod.rs new file mode 100644 index 00000000..b351bca7 --- /dev/null +++ b/patches/openvm-static-verifier/src/hash/mod.rs @@ -0,0 +1,64 @@ +use core::array; +use std::sync::LazyLock; + +use halo2_base::utils::biguint_to_fe; +pub(crate) use openvm_stark_sdk::config::baby_bear_bn254_poseidon2::SPONGE_WIDTH as POSEIDON2_WIDTH; +use openvm_stark_sdk::{ + config::bn254_poseidon2::{ + default_bn254_poseidon2_width2_constants, default_bn254_poseidon2_width3_constants, + Poseidon2Bn254Constants, + }, + openvm_stark_backend::p3_field::PrimeField, +}; + +use crate::Fr; + +pub mod poseidon2; +use poseidon2::Poseidon2Params; + +/// Width-2 compression permutation width. +const COMPRESS_WIDTH: usize = 2; + +/// Convert `Poseidon2Bn254Constants` from stark-backend into halo2 `Poseidon2Params`. +fn bn254_constants_to_params( + constants: &Poseidon2Bn254Constants, +) -> Poseidon2Params { + use openvm_stark_sdk::config::baby_bear_bn254_poseidon2::Bn254Scalar; + + let bn254_to_fr = |elem: &Bn254Scalar| -> Fr { biguint_to_fe(&elem.as_canonical_biguint()) }; + + let initial_ext: Vec<[Fr; WIDTH]> = constants + .initial_external_rc() + .iter() + .map(|rc| array::from_fn(|i| bn254_to_fr(&rc[i]))) + .collect(); + let terminal_ext: Vec<[Fr; WIDTH]> = constants + .terminal_external_rc() + .iter() + .map(|rc| array::from_fn(|i| bn254_to_fr(&rc[i]))) + .collect(); + let internal_rc: Vec = constants.internal_rc().iter().map(bn254_to_fr).collect(); + let mat_internal_diag_m_1 = + array::from_fn(|i| bn254_to_fr(&constants.mat_internal_diag_m_1()[i])); + + let mut external_rc = initial_ext; + external_rc.extend(terminal_ext); + + let rounds_f = external_rc.len(); + let rounds_p = internal_rc.len(); + Poseidon2Params::new( + rounds_f, + rounds_p, + mat_internal_diag_m_1, + external_rc, + internal_rc, + ) +} + +/// Width-3 Poseidon2 params for leaf hashing and transcript sponge. +pub(crate) static POSEIDON2_PARAMS: LazyLock> = + LazyLock::new(|| bn254_constants_to_params(default_bn254_poseidon2_width3_constants())); + +/// Width-2 Poseidon2 params for Merkle compression (gnark-crypto compatible). +pub(crate) static POSEIDON2_COMPRESS_PARAMS: LazyLock> = + LazyLock::new(|| bn254_constants_to_params(default_bn254_poseidon2_width2_constants())); diff --git a/patches/openvm-static-verifier/src/hash/poseidon2.rs b/patches/openvm-static-verifier/src/hash/poseidon2.rs new file mode 100644 index 00000000..3d09911b --- /dev/null +++ b/patches/openvm-static-verifier/src/hash/poseidon2.rs @@ -0,0 +1,238 @@ +//! Halo2 implementation of poseidon2 perm for Bn254 +//! sbox degree 5 + +use halo2_base::{ + gates::{range::RangeChip, GateInstructions, RangeInstructions}, + utils::ScalarField, + AssignedValue, Context, + QuantumCell::{self, Constant}, +}; +pub(crate) use openvm_stark_sdk::config::baby_bear_bn254_poseidon2::{ + BABY_BEAR_RATE as MULTI_FIELD32_RATE, BN254_RATE as POSEIDON2_RATE, DIGEST_WIDTH, +}; + +use crate::{field::baby_bear::ReducedBabyBearWire, Fr}; + +const MULTI_FIELD32_NUM_F_ELMS: usize = MULTI_FIELD32_RATE / POSEIDON2_RATE; + +#[derive(Clone, Debug)] +pub struct Poseidon2State { + pub s: [AssignedValue; T], +} + +#[derive(Debug, Clone)] +pub struct Poseidon2Params { + /// Number of full rounds + pub rounds_f: usize, + pub rounds_p: usize, + pub mat_internal_diag_m_1: [F; T], + pub external_rc: Vec<[F; T]>, + pub internal_rc: Vec, +} + +impl Poseidon2Params { + pub fn new( + rounds_f: usize, + rounds_p: usize, + mat_internal_diag_m_1: [F; T], + external_rc: Vec<[F; T]>, + internal_rc: Vec, + ) -> Self { + Self { + rounds_f, + rounds_p, + mat_internal_diag_m_1, + external_rc, + internal_rc, + } + } +} + +impl Poseidon2State { + pub fn new(state: [AssignedValue; T]) -> Self { + Self { s: state } + } + /// Perform permutation on this state. + /// + /// ATTENTION: inputs.len() needs to be fixed at compile time. + pub fn permutation( + &mut self, + ctx: &mut Context, + gate: &impl GateInstructions, + params: &Poseidon2Params, + ) { + let rounds_f_beginning = params.rounds_f / 2; + + // First half of the full round + self.matmul_external(ctx, gate); + for r in 0..rounds_f_beginning { + self.add_rc(ctx, gate, params.external_rc[r]); + self.sbox(ctx, gate); + self.matmul_external(ctx, gate); + } + + for r in 0..params.rounds_p { + self.s[0] = gate.add(ctx, self.s[0], Constant(params.internal_rc[r])); + self.s[0] = Self::x_power5(ctx, gate, self.s[0]); + self.matmul_internal(ctx, gate, params.mat_internal_diag_m_1); + } + + for r in rounds_f_beginning..params.rounds_f { + self.add_rc(ctx, gate, params.external_rc[r]); + self.sbox(ctx, gate); + self.matmul_external(ctx, gate); + } + } + + fn x_power5( + ctx: &mut Context, + gate: &impl GateInstructions, + x: AssignedValue, + ) -> AssignedValue { + let x2 = gate.mul(ctx, x, x); + let x4 = gate.mul(ctx, x2, x2); + gate.mul(ctx, x, x4) + } + + fn sbox(&mut self, ctx: &mut Context, gate: &impl GateInstructions) { + for x in self.s.iter_mut() { + *x = Self::x_power5(ctx, gate, *x); + } + } + + fn matmul_external(&mut self, ctx: &mut Context, gate: &impl GateInstructions) { + // M_E for T=2: circ(2, 1) = [[2,1],[1,2]] + // M_E for T=3: circ(2, 1, 1) + assert!(T == 2 || T == 3); + + let sum = gate.sum(ctx, self.s.iter().copied()); + for (i, x) in self.s.iter_mut().enumerate() { + // This is the same as `*x = gate.add(ctx, *x, sum)` but we save a cell by reusing + // `sum`: + if i % 2 == 0 { + ctx.assign_region( + [ + QuantumCell::Witness(*x.value() + sum.value()), + QuantumCell::Existing(*x), + QuantumCell::Constant(-F::ONE), + QuantumCell::Existing(sum), + ], + [0], + ); + *x = ctx.get(-4); + } else { + ctx.assign_region( + [ + QuantumCell::Existing(*x), + QuantumCell::Constant(F::ONE), + QuantumCell::Witness(*x.value() + sum.value()), + ], + [-1], + ); + *x = ctx.get(-1); + } + } + } + + fn add_rc( + &mut self, + ctx: &mut Context, + gate: &impl GateInstructions, + round_constants: [F; T], + ) { + for (x, rc) in self.s.iter_mut().zip(round_constants.iter()) { + *x = gate.add(ctx, *x, Constant(*rc)); + } + } + + fn matmul_internal( + &mut self, + ctx: &mut Context, + gate: &impl GateInstructions, + mat_internal_diag_m_1: [F; T], + ) { + assert!(T == 2 || T == 3); + let sum = gate.sum(ctx, self.s.iter().copied()); + #[allow(clippy::needless_range_loop)] + for i in 0..T { + // This is the same as `self.s[i] = gate.mul_add(ctx, self.s[i], + // Constant(mat_internal_diag_m_1[i]), sum)` but we save a cell by reusing `sum`. + if i % 2 == 0 { + ctx.assign_region( + [ + QuantumCell::Witness( + *self.s[i].value() * mat_internal_diag_m_1[i] + sum.value(), + ), + QuantumCell::Existing(self.s[i]), + QuantumCell::Constant(-mat_internal_diag_m_1[i]), + QuantumCell::Existing(sum), + ], + [0], + ); + self.s[i] = ctx.get(-4); + } else { + ctx.assign_region( + [ + QuantumCell::Existing(self.s[i]), + QuantumCell::Constant(mat_internal_diag_m_1[i]), + QuantumCell::Witness( + *self.s[i].value() * mat_internal_diag_m_1[i] + sum.value(), + ), + ], + [-1], + ); + self.s[i] = ctx.get(-1); + } + } + } +} + +pub(crate) fn pack_base_2_31_cells( + ctx: &mut Context, + gate: &impl GateInstructions, + values: &[ReducedBabyBearWire], +) -> AssignedValue { + assert!( + values.len() <= MULTI_FIELD32_NUM_F_ELMS, + "base-2^31 packing supports at most {MULTI_FIELD32_NUM_F_ELMS} limbs" + ); + let base = Fr::from(1u64 << 31); + gate.inner_product( + ctx, + values.iter().map(|value| value.value()), + core::iter::successors(Some(Fr::from(1u64)), |power| Some(*power * base)) + .take(values.len()) + .map(Constant), + ) +} + +pub(crate) fn hash_babybear_slice_to_digest( + ctx: &mut Context, + range: &RangeChip, + values: &[ReducedBabyBearWire], +) -> AssignedValue { + let gate = range.gate(); + let params = &*super::POSEIDON2_PARAMS; + let zero = ctx.load_zero(); + let mut state = Poseidon2State::new(core::array::from_fn(|_| zero)); + for block_chunk in values.chunks(MULTI_FIELD32_RATE) { + for (chunk_id, chunk) in block_chunk.chunks(MULTI_FIELD32_NUM_F_ELMS).enumerate() { + state.s[chunk_id] = pack_base_2_31_cells(ctx, gate, chunk); + } + state.permutation(ctx, gate, params); + } + state.s[0] +} + +pub(crate) fn compress_bn254_digests( + ctx: &mut Context, + range: &RangeChip, + left: AssignedValue, + right: AssignedValue, +) -> AssignedValue { + let gate = range.gate(); + let params = &*super::POSEIDON2_COMPRESS_PARAMS; + let mut state = Poseidon2State::new([left, right]); + state.permutation(ctx, gate, params); + state.s[0] +} diff --git a/patches/openvm-static-verifier/src/keygen.rs b/patches/openvm-static-verifier/src/keygen.rs new file mode 100644 index 00000000..3a795026 --- /dev/null +++ b/patches/openvm-static-verifier/src/keygen.rs @@ -0,0 +1,198 @@ +use halo2_base::{ + gates::circuit::CircuitBuilderStage, + halo2_proofs::plonk::{keygen_pk, keygen_vk}, +}; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig, + openvm_stark_backend::proof::Proof, +}; +#[cfg(feature = "evm-prove")] +use serde::{Deserialize, Serialize}; + +use crate::{ + circuit::StaticVerifierCircuit, + config::StaticVerifierShape, + prover::{Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning, StaticVerifierProof}, +}; + +impl StaticVerifierCircuit { + /// Run keygen to produce a [`Halo2ProvingPinning`]. + /// + /// The `representative_proof` is used as a witness for keygen; any valid proof for this static + /// circuit shape will do. + pub fn keygen( + &self, + params: &Halo2Params, + shape: &StaticVerifierShape, + representative_proof: &Proof, + ) -> Halo2ProvingPinning { + let mut builder = Self::builder(CircuitBuilderStage::Keygen, shape); + let public_inputs = self.populate(&mut builder, representative_proof); + + let config_params = builder.calculate_params(Some(shape.minimum_rows)); + + let vk = keygen_vk(params, &builder).expect("keygen_vk should succeed"); + let pk = keygen_pk(params, vk, &builder).expect("keygen_pk should succeed"); + let break_points = builder.break_points(); + + Halo2ProvingPinning { + pk, + metadata: Halo2ProvingMetadata { + config_params, + break_points, + num_pvs: vec![public_inputs.to_vec().len()], + }, + } + } +} + +/// High-level proving key that owns a [`StaticVerifierCircuit`], [`Halo2ProvingPinning`], and +/// [`StaticVerifierShape`]. +#[derive(Clone)] +pub struct StaticVerifierProvingKey { + pub circuit: StaticVerifierCircuit, + pub pinning: Halo2ProvingPinning, + pub shape: StaticVerifierShape, +} + +impl StaticVerifierProvingKey { + /// Run keygen and return a proving key that can be reused for multiple proofs. + pub fn keygen( + params: &Halo2Params, + shape: StaticVerifierShape, + circuit: StaticVerifierCircuit, + representative_proof: &Proof, + ) -> Self { + let pinning = circuit.keygen(params, &shape, representative_proof); + Self { + circuit, + pinning, + shape, + } + } + + /// Generate a proof using the stored pinning and shape. + pub fn prove(&self, params: &Halo2Params, proof: &Proof) -> StaticVerifierProof { + self.circuit + .prove(params, &self.pinning, &self.shape, proof) + } + + /// Verify a proof against this proving key's verifying key. + pub fn verify(&self, params: &Halo2Params, proof: &StaticVerifierProof) -> bool { + StaticVerifierCircuit::verify(params, self.pinning.pk.get_vk(), proof) + } +} + +// --- EVM support (feature-gated) --- + +#[cfg(feature = "evm-prove")] +use halo2_base::{ + gates::circuit::builder::BaseCircuitBuilder, halo2_proofs::halo2curves::bn256::Fr, +}; +#[cfg(feature = "evm-prove")] +use snark_verifier_sdk::{ + evm::{gen_evm_proof_shplonk, gen_evm_verifier_sol_code}, + SHPLONK, +}; + +/// EVM-compatible proof consisting of instances and raw proof bytes. +#[cfg(feature = "evm-prove")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RawEvmProof { + pub instances: Vec, + pub proof: Vec, +} + +#[cfg(feature = "evm-prove")] +impl StaticVerifierProvingKey { + /// Generate a Solidity verifier contract for this circuit. + pub fn generate_fallback_evm_verifier(&self, params: &Halo2Params) -> String { + gen_evm_verifier_sol_code::, SHPLONK>( + params, + self.pinning.pk.get_vk(), + self.pinning.metadata.num_pvs.clone(), + ) + } + + /// Produce a [`Snark`](snark_verifier_sdk::Snark) for consumption by the wrapper circuit. + /// + /// Unlike [`prove_for_evm_unwrapped`](Self::prove_for_evm_unwrapped), this + /// returns a `Snark` (not a raw EVM proof), which should be fed into + /// [`Halo2WrapperProvingKey::prove_for_evm`](crate::wrapper::Halo2WrapperProvingKey::prove_for_evm). + pub fn prove_wrapped( + &self, + params: &Halo2Params, + proof: &Proof, + ) -> snark_verifier_sdk::Snark { + let mut builder = BaseCircuitBuilder::prover( + self.pinning.metadata.config_params.clone(), + self.pinning.metadata.break_points.clone(), + ) + .use_instance_columns(self.shape.instance_columns); + + let _public_inputs = self.circuit.populate(&mut builder, proof); + + snark_verifier_sdk::halo2::gen_snark_shplonk( + params, + &self.pinning.pk, + builder, + None::<&str>, + ) + } + + /// Generate a dummy snark for wrapper keygen. + pub fn generate_dummy_snark( + &self, + reader: &impl crate::wrapper::Halo2ParamsReader, + ) -> snark_verifier_sdk::Snark { + let k = self.pinning.metadata.config_params.k; + let params = reader.read_params(k); + snark_verifier_sdk::halo2::gen_dummy_snark_from_vk::( + ¶ms, + self.pinning.pk.get_vk(), + self.pinning.metadata.num_pvs.clone(), + None, + ) + } + + /// Generate an EVM-compatible proof directly (one-step, no wrapper circuit). + pub fn prove_for_evm_unwrapped( + &self, + params: &Halo2Params, + proof: &Proof, + ) -> RawEvmProof { + let mut builder = BaseCircuitBuilder::prover( + self.pinning.metadata.config_params.clone(), + self.pinning.metadata.break_points.clone(), + ) + .use_instance_columns(self.shape.instance_columns); + + let public_inputs = self.circuit.populate(&mut builder, proof); + let instances_vec = public_inputs.to_vec(); + + let snark = gen_evm_proof_shplonk( + params, + &self.pinning.pk, + builder, + vec![instances_vec.clone()], + ); + + RawEvmProof { + instances: instances_vec, + proof: snark, + } + } +} + +/// Verify an EVM proof using a deployed verifier contract. +/// +/// Returns the gas used on success, or an error message on failure. +#[cfg(feature = "evm-verify")] +pub fn evm_verify(deployment_code: &[u8], proof: &RawEvmProof) -> Result { + snark_verifier_sdk::evm::evm_verify( + deployment_code.to_vec(), + vec![proof.instances.clone()], + proof.proof.clone(), + ) + .map_err(|e| format!("EVM verification failed: {e}")) +} diff --git a/patches/openvm-static-verifier/src/lib.rs b/patches/openvm-static-verifier/src/lib.rs new file mode 100644 index 00000000..e63820fb --- /dev/null +++ b/patches/openvm-static-verifier/src/lib.rs @@ -0,0 +1,49 @@ +//! Static verifier circuit for OpenVM root STARK proof. +//! The verifier circuit is implemented using Halo2 via the `halo2-base` eDSL. +//! +//! Static means that the circuit hard codes the following and does not allow them to vary as part +//! of the input: +//! - The child verifying key, including all system parameters +//! - The trace heights of the root proof (the static verifier circuit's input) are **fixed**. The +//! heights of each AIR are fixed. Consequently the permutation order of AIRs sorted by height is +//! fixed. +//! - The trace heights of the root proof are all nonzero. In other words no AIR in the child +//! verifying key is optional. +//! +//! End-to-end Halo2 tests that use full [`StaticVerifierCircuit::populate`] (continuations public +//! values + symbolic DAG cached-commit pin) belong in `openvm-sdk` integration tests; this crate +//! keeps a lighter FibFixture + KZG roundtrip via +//! [`StaticVerifierCircuit::populate_verify_stark_constraints`]. +#![forbid(unsafe_code)] + +#[cfg(feature = "cell-profiling")] +mod context_tree; +pub mod profiling; + +mod circuit; +#[cfg(feature = "evm-prove")] +pub mod codec; +pub mod config; +pub mod field; +pub mod hash; +pub mod keygen; +pub mod prover; +pub mod stages; +pub mod transcript; +mod utils; +#[cfg(feature = "evm-prove")] +pub mod wrapper; + +pub use circuit::{compute_dag_onion_commit, StaticCircuitParamsError, StaticVerifierCircuit}; +pub use config::{ + StaticVerifierShape, STATIC_VERIFIER_LOOKUP_ADVICE_COLS, STATIC_VERIFIER_NUM_ADVICE_COLS, +}; +pub use halo2_base::halo2_proofs::halo2curves::bn256::Fr; +pub use keygen::StaticVerifierProvingKey; +pub use openvm_stark_sdk::config::baby_bear_bn254_poseidon2::{EF as RootEF, F as RootF}; +pub use prover::{Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning, StaticVerifierProof}; +pub use stages::proof_shape::log_heights_per_air_from_proof; +#[cfg(feature = "evm-prove")] +pub use wrapper::{ + EvmVerifierByteCode, FallbackEvmVerifier, Halo2ParamsReader, Halo2WrapperProvingKey, +}; diff --git a/patches/openvm-static-verifier/src/profiling.rs b/patches/openvm-static-verifier/src/profiling.rs new file mode 100644 index 00000000..2fdfab91 --- /dev/null +++ b/patches/openvm-static-verifier/src/profiling.rs @@ -0,0 +1,83 @@ +//! Cell-count profiling for the static verifier circuit. +//! +//! When the `cell-profiling` feature is enabled, [`CellProfiler`] tracks advice cell allocations +//! across pipeline stages and can generate flamegraph SVGs via `inferno`. +//! +//! When the feature is disabled, all methods are `#[inline(always)]` no-ops with zero overhead. + +#[cfg(feature = "cell-profiling")] +mod enabled { + use std::{fs::File, io::BufWriter}; + + use crate::context_tree::ContextTree; + + pub struct CellProfiler { + tree: ContextTree, + } + + impl CellProfiler { + pub fn new(label: &str, cell_count: usize) -> Self { + Self { + tree: ContextTree::with_name(label, cell_count), + } + } + + pub fn push(&mut self, name: &str, cell_count: usize) { + self.tree.push(name, tracing::Level::DEBUG, cell_count); + } + + pub fn pop(&mut self, cell_count: usize) { + self.tree.pop(cell_count); + } + + pub fn print(&self, cell_count: usize) { + self.tree.print(cell_count); + } + + pub fn write_flamegraph(&self, path: &str, title: &str, cell_count: usize) { + let file = File::create(path).expect("Failed to create flamegraph file"); + let mut writer = BufWriter::new(file); + self.tree + .write_flamegraph(&mut writer, title, cell_count, false); + } + + pub fn write_flamegraph_reversed(&self, path: &str, title: &str, cell_count: usize) { + let file = File::create(path).expect("Failed to create flamegraph file"); + let mut writer = BufWriter::new(file); + self.tree + .write_flamegraph(&mut writer, title, cell_count, true); + } + } +} + +#[cfg(not(feature = "cell-profiling"))] +mod disabled { + pub struct CellProfiler; + + impl CellProfiler { + #[inline(always)] + pub fn new(_label: &str, _cell_count: usize) -> Self { + Self + } + + #[inline(always)] + pub fn push(&mut self, _name: &str, _cell_count: usize) {} + + #[inline(always)] + pub fn pop(&mut self, _cell_count: usize) {} + + #[inline(always)] + pub fn print(&self, _cell_count: usize) {} + + #[inline(always)] + pub fn write_flamegraph(&self, _path: &str, _title: &str, _cell_count: usize) {} + + #[inline(always)] + pub fn write_flamegraph_reversed(&self, _path: &str, _title: &str, _cell_count: usize) {} + } +} + +#[cfg(not(feature = "cell-profiling"))] +pub use disabled::CellProfiler; +#[cfg(feature = "cell-profiling")] +pub use enabled::CellProfiler; diff --git a/patches/openvm-static-verifier/src/prover.rs b/patches/openvm-static-verifier/src/prover.rs new file mode 100644 index 00000000..33e72b5d --- /dev/null +++ b/patches/openvm-static-verifier/src/prover.rs @@ -0,0 +1,180 @@ +use halo2_base::{ + gates::{ + circuit::{builder::BaseCircuitBuilder, BaseCircuitParams, CircuitBuilderStage}, + flex_gate::MultiPhaseThreadBreakPoints, + }, + halo2_proofs::{ + dev::MockProver, + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::{create_proof, verify_proof, ProvingKey, VerifyingKey}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, + }, + }, +}; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig, + openvm_stark_backend::proof::Proof, +}; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; +use serde::{Deserialize, Serialize}; + +use crate::{circuit::StaticVerifierCircuit, config::StaticVerifierShape}; + +/// KZG parameters for the Halo2 BN256 proving system. +pub type Halo2Params = ParamsKZG; + +/// Serializable metadata that accompanies a Halo2 proving key. +/// +/// Stores everything needed to reconstruct a prover builder (config params and +/// break points) without the heavyweight [`ProvingKey`] itself. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Halo2ProvingMetadata { + pub config_params: BaseCircuitParams, + pub break_points: MultiPhaseThreadBreakPoints, + pub num_pvs: Vec, +} + +/// A proving key together with the metadata needed to reconstruct prover +/// circuits. +#[derive(Debug, Clone)] +pub struct Halo2ProvingPinning { + pub pk: ProvingKey, + pub metadata: Halo2ProvingMetadata, +} + +/// Output of [`StaticVerifierCircuit::prove`]. +pub struct StaticVerifierProof { + pub proof_bytes: Vec, + pub public_inputs: Vec, +} + +impl StaticVerifierCircuit { + /// Create a [`BaseCircuitBuilder`] configured for the given `stage` and + /// `shape`. + pub fn builder( + stage: CircuitBuilderStage, + shape: &StaticVerifierShape, + ) -> BaseCircuitBuilder { + BaseCircuitBuilder::from_stage(stage) + .use_k(shape.k) + .use_lookup_bits(shape.lookup_bits) + .use_instance_columns(shape.instance_columns) + } + + /// Run the [`MockProver`] and panic if any constraint is unsatisfied. + /// + /// Uses full [`Self::populate`]. Continuations-shaped end-to-end coverage is in `openvm-sdk` + /// integration tests. + pub fn mock(&self, shape: &StaticVerifierShape, proof: &Proof) { + let mut builder = Self::builder(CircuitBuilderStage::Mock, shape); + let public_inputs = self.populate(&mut builder, proof); + + let _ = builder.calculate_params(Some(shape.minimum_rows)); + + let prover = MockProver::run(shape.k as u32, &builder, vec![public_inputs.to_vec()]) + .expect("MockProver should initialize"); + prover.assert_satisfied(); + } + + /// Generate a Halo2 proof using a previously computed [`Halo2ProvingPinning`]. + /// + /// Uses full [`Self::populate`]. Continuations-shaped proving is covered in `openvm-sdk` + /// integration tests. + pub fn prove( + &self, + params: &Halo2Params, + pinning: &Halo2ProvingPinning, + shape: &StaticVerifierShape, + proof: &Proof, + ) -> StaticVerifierProof { + let mut builder = BaseCircuitBuilder::prover( + pinning.metadata.config_params.clone(), + pinning.metadata.break_points.clone(), + ); + builder = builder.use_instance_columns(shape.instance_columns); + + let public_inputs = self.populate(&mut builder, proof); + let public_inputs = public_inputs.to_vec(); + + let rng = ChaCha20Rng::from_seed(Default::default()); + let instances: &[&[Fr]] = &[&public_inputs]; + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255<_>, + _, + Blake2bWrite, G1Affine, _>, + _, + >( + params, + &pinning.pk, + &[builder], + &[instances], + rng, + &mut transcript, + ) + .expect("Halo2 proof generation should succeed"); + + StaticVerifierProof { + proof_bytes: transcript.finalize(), + public_inputs, + } + } + + /// Verify a Halo2 proof against a verifying key. + pub fn verify( + params: &Halo2Params, + vk: &VerifyingKey, + proof: &StaticVerifierProof, + ) -> bool { + let verifier_params = params.verifier_params(); + let strategy = SingleStrategy::new(params); + let mut transcript = + Blake2bRead::<_, _, Challenge255<_>>::init(proof.proof_bytes.as_slice()); + // One entry per circuit; inner slice length must match `num_instance_columns` (here: 0). + let no_instance_cols: &[&[Fr]] = &[]; + let ok = if proof.public_inputs.is_empty() { + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + verifier_params, + vk, + strategy, + &[no_instance_cols], + &mut transcript, + ) + } else { + let instances: &[&[Fr]] = &[&proof.public_inputs]; + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >(verifier_params, vk, strategy, &[instances], &mut transcript) + }; + ok.is_ok() + } +} + +impl Halo2ProvingPinning { + /// Return the proving key as raw Halo2 bytes. + pub fn pk_to_bytes(&self) -> Vec { + use halo2_base::halo2_proofs::SerdeFormat; + self.pk.to_bytes(SerdeFormat::RawBytes) + } +} diff --git a/patches/openvm-static-verifier/src/stages/batch_constraints/mod.rs b/patches/openvm-static-verifier/src/stages/batch_constraints/mod.rs new file mode 100644 index 00000000..a01455cd --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/batch_constraints/mod.rs @@ -0,0 +1,1189 @@ +use std::{collections::BTreeMap, iter::zip}; + +use halo2_base::Context; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig, + openvm_stark_backend::{ + air_builders::symbolic::{ + symbolic_variable::{Entry, SymbolicVariable}, + SymbolicExpressionNode, + }, + calculate_n_logup, + keygen::types::MultiStarkVerifyingKey0, + p3_field::{Field, PrimeCharacteristicRing, TwoAdicField}, + }, +}; + +use crate::{ + field::baby_bear::{ + BabyBearChip, BabyBearExtChip, BabyBearExtWire, BabyBearWire, ReducedBabyBearExtWire, + ReducedBabyBearWire, + }, + profiling::CellProfiler, + stages::shared_math::{column_openings_by_rot_assigned, horner_eval_ext_poly_assigned}, + transcript::TranscriptChip, + Fr, RootEF, RootF, +}; + +#[derive(Clone, Debug)] +pub struct BatchConstraintIntermediatesWire { + pub column_openings: Vec>>, + pub r: Vec, +} + +#[derive(Clone, Debug)] +pub struct GkrProofWire { + pub logup_pow_witness: ReducedBabyBearWire, + pub q0_claim: ReducedBabyBearExtWire, + pub claims_per_layer: Vec<[ReducedBabyBearExtWire; 4]>, + pub sumcheck_polys: Vec>, +} + +#[derive(Clone, Debug)] +pub struct BatchConstraintProofWire { + pub numerator_term_per_air: Vec, + pub denominator_term_per_air: Vec, + pub univariate_round_coeffs: Vec, + pub sumcheck_round_polys: Vec>, + pub column_openings: Vec>>, +} + +pub(crate) fn load_gkr_proof_wire( + ctx: &mut Context, + base_chip: &BabyBearChip, + ext_chip: &BabyBearExtChip, + gkr_proof: &openvm_stark_sdk::openvm_stark_backend::proof::GkrProof, +) -> GkrProofWire { + let logup_pow_witness = base_chip.load_reduced_witness(ctx, gkr_proof.logup_pow_witness); + let q0_claim = ext_chip.load_reduced_witness(ctx, gkr_proof.q0_claim); + let claims_per_layer = gkr_proof + .claims_per_layer + .iter() + .map(|claims| { + [ + ext_chip.load_reduced_witness(ctx, claims.p_xi_0), + ext_chip.load_reduced_witness(ctx, claims.q_xi_0), + ext_chip.load_reduced_witness(ctx, claims.p_xi_1), + ext_chip.load_reduced_witness(ctx, claims.q_xi_1), + ] + }) + .collect::>(); + let sumcheck_polys = gkr_proof + .sumcheck_polys + .iter() + .map(|poly| { + poly.iter() + .map(|evals| evals.map(|value| ext_chip.load_reduced_witness(ctx, value))) + .collect::>() + }) + .collect::>(); + GkrProofWire { + logup_pow_witness, + q0_claim, + claims_per_layer, + sumcheck_polys, + } +} + +pub(crate) fn load_batch_constraint_proof_wire( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + batch_proof: &openvm_stark_sdk::openvm_stark_backend::proof::BatchConstraintProof, +) -> BatchConstraintProofWire { + let numerator_term_per_air = batch_proof + .numerator_term_per_air + .iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>(); + let denominator_term_per_air = batch_proof + .denominator_term_per_air + .iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>(); + let univariate_round_coeffs = batch_proof + .univariate_round_coeffs + .iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>(); + let sumcheck_round_polys = batch_proof + .sumcheck_round_polys + .iter() + .map(|poly| { + poly.iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>() + }) + .collect::>(); + let column_openings = batch_proof + .column_openings + .iter() + .map(|per_air| { + per_air + .iter() + .map(|part| { + part.iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>() + }) + .collect::>() + }) + .collect::>(); + BatchConstraintProofWire { + numerator_term_per_air, + denominator_term_per_air, + univariate_round_coeffs, + sumcheck_round_polys, + column_openings, + } +} + +fn eval_lagrange_on_integer_grid( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + point: &BabyBearExtWire, + evals: &[BabyBearExtWire], +) -> BabyBearExtWire { + let n = evals.len().saturating_sub(1); + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let x_grid = (0..=n) + .map(|j| { + ext_chip + .base() + .load_constant(ctx, RootF::from_u64(j as u64)) + }) + .collect::>(); + let mut acc = ext_chip.zero(ctx); + for (i, eval_i) in evals.iter().enumerate() { + let mut basis = one; + let mut denom = RootF::ONE; + #[allow(clippy::needless_range_loop)] + for j in 0..=n { + if i == j { + continue; + } + let mut x_minus_j = *point; + x_minus_j.0[0] = ext_chip.base().sub(ctx, x_minus_j.0[0], x_grid[j]); + basis = ext_chip.mul(ctx, basis, x_minus_j); + + let diff = if i >= j { + RootF::from_usize(i - j) + } else { + -RootF::from_usize(j - i) + }; + denom *= diff; + } + let denom_inv = denom.inverse(); + let basis = ext_chip.mul_base_const(ctx, basis, denom_inv); + let term = ext_chip.mul(ctx, *eval_i, basis); + acc = ext_chip.add(ctx, acc, term); + } + acc +} + +fn progression_exp_2_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + m: &BabyBearExtWire, + l: usize, +) -> BabyBearExtWire { + let mut pow = *m; + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut sum = one; + for _ in 0..l { + let one_plus_pow = ext_chip.add(ctx, one, pow); + sum = ext_chip.mul(ctx, sum, one_plus_pow); + pow = ext_chip.mul(ctx, pow, pow); + } + sum +} + +pub(crate) fn eval_eq_mle_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + x: &[BabyBearExtWire], + y: &[BabyBearExtWire], +) -> BabyBearExtWire { + assert_eq!(x.len(), y.len(), "eq_mle vector length mismatch"); + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut acc = one; + // Rewrite: 2xy - x + (1-y) = (1-y) + x(2y-1). + // This replaces one ext×ext mul (xy) + scalar_mul (2*xy) + // with just a scalar_mul (2*y) + one ext×ext mul (x * (2y-1)). + for (x_i, y_i) in x.iter().zip(y.iter()) { + let two_y_minus_one = ext_chip.mul_base_const(ctx, *y_i, RootF::TWO); + let two_y_minus_one = ext_chip.sub(ctx, two_y_minus_one, one); + let x_term = ext_chip.mul(ctx, *x_i, two_y_minus_one); + let one_minus_y = ext_chip.sub(ctx, one, *y_i); + let factor = ext_chip.add(ctx, one_minus_y, x_term); + acc = ext_chip.mul(ctx, acc, factor); + } + acc +} + +pub(crate) fn eval_eq_mle_ef_f_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + x: &[BabyBearExtWire], + y: &[BabyBearWire], +) -> BabyBearExtWire { + assert_eq!(x.len(), y.len(), "eq_mle vector length mismatch"); + let one_base = ext_chip.base().one(ctx); + let mut acc = ext_chip.from_base_const(ctx, RootF::ONE); + // Rewrite: 2xy - x + (1-y) = (1-y) + x(2y-1). + // Since y is base-field: compute 2y-1 as a base-field constant, + // then scalar_mul x by it. Saves one scalar_mul (the old xy + 2*xy chain). + for (x_i, y_i) in x.iter().zip(y.iter()) { + let two_y = ext_chip.base().mul_const(ctx, *y_i, RootF::TWO); + let two_y_minus_one = ext_chip.base().sub(ctx, two_y, one_base); + let x_term = ext_chip.scalar_mul(ctx, *x_i, two_y_minus_one); + let one_minus_y = ext_chip.base().sub(ctx, one_base, *y_i); + let mut factor = x_term; + factor.0[0] = ext_chip.base().add(ctx, factor.0[0], one_minus_y); + acc = ext_chip.mul(ctx, acc, factor); + } + acc +} + +pub(crate) fn eval_eq_mle_binary_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + x: &[BabyBearExtWire], + y_bits: &[bool], +) -> BabyBearExtWire { + assert_eq!( + x.len(), + y_bits.len(), + "eq_mle binary vector length mismatch", + ); + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut acc = one; + for (x_i, bit) in x.iter().zip(y_bits.iter().copied()) { + let factor = if bit { + *x_i + } else { + ext_chip.sub(ctx, one, *x_i) + }; + acc = ext_chip.mul(ctx, acc, factor); + } + acc +} + +pub(crate) fn eval_eq_uni_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + l_skip: usize, + x: &BabyBearExtWire, + y: &BabyBearExtWire, +) -> BabyBearExtWire { + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut res = one; + let mut x_pow = *x; + let mut y_pow = *y; + for _ in 0..l_skip { + let x_plus_y = ext_chip.add(ctx, x_pow, y_pow); + let x_minus_one = ext_chip.sub(ctx, x_pow, one); + let y_minus_one = ext_chip.sub(ctx, y_pow, one); + let correction = ext_chip.mul(ctx, x_minus_one, y_minus_one); + let scaled_res = ext_chip.mul(ctx, x_plus_y, res); + res = ext_chip.add(ctx, scaled_res, correction); + x_pow = ext_chip.mul(ctx, x_pow, x_pow); + y_pow = ext_chip.mul(ctx, y_pow, y_pow); + } + let half_pow_l = RootF::ONE.halve().exp_u64(l_skip as u64); + ext_chip.mul_base_const(ctx, res, half_pow_l) +} + +pub(crate) fn eval_eq_uni_at_one_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + l_skip: usize, + x: &BabyBearExtWire, +) -> BabyBearExtWire { + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut res = one; + let mut x_pow = *x; + for _ in 0..l_skip { + let x_plus_one = ext_chip.add(ctx, x_pow, one); + res = ext_chip.mul(ctx, res, x_plus_one); + x_pow = ext_chip.mul(ctx, x_pow, x_pow); + } + let half_pow_l = RootF::ONE.halve().exp_u64(l_skip as u64); + ext_chip.mul_base_const(ctx, res, half_pow_l) +} + +fn eval_eq_sharp_uni_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + omega_skip_pows: &[RootF], + xi_1: &[BabyBearExtWire], + z: &BabyBearExtWire, +) -> BabyBearExtWire { + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut eq_xi_evals = vec![ext_chip.zero(ctx); 1usize << xi_1.len()]; + eq_xi_evals[0] = one; + + // Match `evals_eq_hypercube_serial` ordering from the native verifier: + // mask bit `i` corresponds to `xi_1[i]`. + for (i, xi) in xi_1.iter().enumerate() { + let span = 1usize << i; + let one_minus_xi = ext_chip.sub(ctx, one, *xi); + for idx in 0..span { + let prev = eq_xi_evals[idx]; + let lo = ext_chip.mul(ctx, prev, one_minus_xi); + let hi = ext_chip.mul(ctx, prev, *xi); + eq_xi_evals[idx] = lo; + eq_xi_evals[span + idx] = hi; + } + } + + assert_eq!( + eq_xi_evals.len(), + omega_skip_pows.len(), + "eq_sharp eval table width mismatch", + ); + + let mut res = ext_chip.zero(ctx); + let l_skip = xi_1.len(); + for (omega_pow, eq_xi_eval) in omega_skip_pows.iter().zip(eq_xi_evals.iter()) { + let omega_ext = ext_chip.from_base_const(ctx, *omega_pow); + let eq_uni = eval_eq_uni_assigned(ctx, ext_chip, l_skip, z, &omega_ext); + let term = ext_chip.mul(ctx, eq_uni, *eq_xi_eval); + res = ext_chip.add(ctx, res, term); + } + res +} + +pub(crate) fn eval_eq_prism_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + l_skip: usize, + x: &[BabyBearExtWire], + y: &[BabyBearExtWire], +) -> BabyBearExtWire { + assert!( + !x.is_empty() && !y.is_empty(), + "eq_prism vectors must be non-empty", + ); + let eq_uni = eval_eq_uni_assigned(ctx, ext_chip, l_skip, &x[0], &y[0]); + let eq_mle = eval_eq_mle_assigned(ctx, ext_chip, &x[1..], &y[1..]); + ext_chip.mul(ctx, eq_uni, eq_mle) +} + +fn eval_eq_rot_cube_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + x: &[BabyBearExtWire], + y: &[BabyBearExtWire], +) -> (BabyBearExtWire, BabyBearExtWire) { + assert_eq!(x.len(), y.len(), "eq_rot_cube vector length mismatch"); + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut rot = one; + let mut eq = one; + for i in (0..x.len()).rev() { + let one_minus_y = ext_chip.sub(ctx, one, y[i]); + let one_minus_x = ext_chip.sub(ctx, one, x[i]); + let x_times = ext_chip.mul(ctx, x[i], one_minus_y); + let term1 = ext_chip.mul(ctx, x_times, eq); + let y_times = ext_chip.mul(ctx, one_minus_x, y[i]); + let term2 = ext_chip.mul(ctx, y_times, rot); + rot = ext_chip.add(ctx, term1, term2); + + let xy = ext_chip.mul(ctx, x[i], y[i]); + let one_minus_xy = ext_chip.mul(ctx, one_minus_x, one_minus_y); + let eq_factor = ext_chip.add(ctx, xy, one_minus_xy); + eq = ext_chip.mul(ctx, eq, eq_factor); + } + (eq, rot) +} + +pub(crate) fn eval_rot_kernel_prism_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + l_skip: usize, + x: &[BabyBearExtWire], + y: &[BabyBearExtWire], +) -> BabyBearExtWire { + assert!( + !x.is_empty() && !y.is_empty(), + "rot-kernel vectors must be non-empty", + ); + let omega = RootF::two_adic_generator(l_skip); + let y0_omega = ext_chip.mul_base_const(ctx, y[0], omega); + let eq_uni_rot = eval_eq_uni_assigned(ctx, ext_chip, l_skip, &x[0], &y0_omega); + let (eq_cube, rot_cube) = eval_eq_rot_cube_assigned(ctx, ext_chip, &x[1..], &y[1..]); + let term_a = ext_chip.mul(ctx, eq_uni_rot, eq_cube); + + let eq_uni_x_one = eval_eq_uni_at_one_assigned(ctx, ext_chip, l_skip, &x[0]); + let eq_uni_y_one = eval_eq_uni_at_one_assigned(ctx, ext_chip, l_skip, &y0_omega); + let rot_minus_eq = ext_chip.sub(ctx, rot_cube, eq_cube); + let eq_uni_product = ext_chip.mul(ctx, eq_uni_x_one, eq_uni_y_one); + let term_b = ext_chip.mul(ctx, eq_uni_product, rot_minus_eq); + ext_chip.add(ctx, term_a, term_b) +} + +fn interpolate_linear_at_01_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + eval0: &BabyBearExtWire, + eval1: &BabyBearExtWire, + x: &BabyBearExtWire, +) -> BabyBearExtWire { + let delta = ext_chip.sub(ctx, *eval1, *eval0); + let scaled = ext_chip.mul(ctx, delta, *x); + ext_chip.add(ctx, scaled, *eval0) +} + +fn interpolate_cubic_at_0123_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + evals: [&BabyBearExtWire; 4], + x: &BabyBearExtWire, +) -> BabyBearExtWire { + let inv6 = RootF::from_u64(6).inverse(); + let s1 = ext_chip.sub(ctx, *evals[1], *evals[0]); + let s2 = ext_chip.sub(ctx, *evals[2], *evals[0]); + let s3 = ext_chip.sub(ctx, *evals[3], *evals[0]); + + let s2_minus_s1 = ext_chip.sub(ctx, s2, s1); + let triple = ext_chip.mul_base_const(ctx, s2_minus_s1, RootF::from_u64(3)); + let d3 = ext_chip.sub(ctx, s3, triple); + + let p = ext_chip.mul_base_const(ctx, d3, inv6); + let s2_minus_d3 = ext_chip.sub(ctx, s2, d3); + let half = RootF::ONE.halve(); + let q_half = ext_chip.mul_base_const(ctx, s2_minus_d3, half); + let q = ext_chip.sub(ctx, q_half, s1); + let p_plus_q = ext_chip.add(ctx, p, q); + let r = ext_chip.sub(ctx, s1, p_plus_q); + + let p_mul_x = ext_chip.mul(ctx, p, *x); + let px_plus_q = ext_chip.add(ctx, p_mul_x, q); + let quad_mul_x = ext_chip.mul(ctx, px_plus_q, *x); + let quad = ext_chip.add(ctx, quad_mul_x, r); + let cubic = ext_chip.mul(ctx, quad, *x); + ext_chip.add(ctx, cubic, *evals[0]) +} + +#[derive(Clone)] +struct ViewPairWire { + local: BabyBearExtWire, + next: BabyBearExtWire, +} + +impl From<(BabyBearExtWire, BabyBearExtWire)> for ViewPairWire { + fn from((local, next): (BabyBearExtWire, BabyBearExtWire)) -> Self { + Self { local, next } + } +} + +struct ConstraintEvaluatorWire<'a> { + preprocessed: Option<&'a [ViewPairWire]>, + partitioned_main: &'a [Vec], + is_first_row: BabyBearExtWire, + is_last_row: BabyBearExtWire, + public_values: &'a [ReducedBabyBearWire], +} + +impl ConstraintEvaluatorWire<'_> { + fn eval_var( + &self, + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + symbolic_var: SymbolicVariable, + ) -> BabyBearExtWire { + let index = symbolic_var.index; + match symbolic_var.entry { + Entry::Preprocessed { offset } => { + let value = &self.preprocessed.unwrap()[index]; + match offset { + 0 => value.local, + 1 => value.next, + _ => panic!("unsupported preprocessed rotation offset {offset}"), + } + } + Entry::Main { part_index, offset } => { + let value = &self.partitioned_main[part_index][index]; + match offset { + 0 => value.local, + 1 => value.next, + _ => panic!("unsupported main rotation offset {offset}"), + } + } + Entry::Public => { + let value = self.public_values[index]; + ext_chip.from_base_var(ctx, value.into()) + } + _ => panic!("invalid constraint"), + } + } +} + +fn eval_symbolic_nodes_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + evaluator: &ConstraintEvaluatorWire<'_>, + nodes: &[SymbolicExpressionNode], +) -> Vec { + let mut exprs: Vec = Vec::with_capacity(nodes.len()); + for node in nodes { + let expr = match node { + SymbolicExpressionNode::Variable(var) => evaluator.eval_var(ctx, ext_chip, *var), + SymbolicExpressionNode::Constant(c) => ext_chip.from_base_const(ctx, *c), + SymbolicExpressionNode::Add { + left_idx, + right_idx, + .. + } => ext_chip.add(ctx, exprs[*left_idx], exprs[*right_idx]), + SymbolicExpressionNode::Sub { + left_idx, + right_idx, + .. + } => ext_chip.sub(ctx, exprs[*left_idx], exprs[*right_idx]), + SymbolicExpressionNode::Neg { idx, .. } => ext_chip.neg(ctx, exprs[*idx]), + SymbolicExpressionNode::Mul { + left_idx, + right_idx, + .. + } => { + let left_const = match &nodes[*left_idx] { + SymbolicExpressionNode::Constant(c) => Some(*c), + _ => None, + }; + let right_const = match &nodes[*right_idx] { + SymbolicExpressionNode::Constant(c) => Some(*c), + _ => None, + }; + match (left_const, right_const) { + (Some(lc), Some(rc)) => ext_chip.from_base_const(ctx, lc * rc), + (Some(c), None) => ext_chip.mul_base_const(ctx, exprs[*right_idx], c), + (None, Some(c)) => ext_chip.mul_base_const(ctx, exprs[*left_idx], c), + (None, None) => ext_chip.mul(ctx, exprs[*left_idx], exprs[*right_idx]), + } + } + SymbolicExpressionNode::IsFirstRow => evaluator.is_first_row, + SymbolicExpressionNode::IsLastRow => evaluator.is_last_row, + SymbolicExpressionNode::IsTransition => { + let one = ext_chip.from_base_const(ctx, RootF::ONE); + ext_chip.sub(ctx, one, evaluator.is_last_row) + } + }; + exprs.push(expr); + } + exprs +} + +fn local_next_opening_views( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + openings: &[ReducedBabyBearExtWire], + need_rot: bool, +) -> Vec { + let openings = openings + .iter() + .map(BabyBearExtWire::from) + .collect::>(); + column_openings_by_rot_assigned(ctx, ext_chip, &openings, need_rot) + .into_iter() + .map(ViewPairWire::from) + .collect() +} + +fn observe_layer_claims_assigned( + ctx: &mut Context, + transcript: &mut TranscriptChip, + claims: &[ReducedBabyBearExtWire], +) { + for claim in claims { + transcript.observe_ext(ctx, claim); + } +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn constrain_batch_constraints_verification( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + transcript: &mut TranscriptChip, + mvk0: &MultiStarkVerifyingKey0, + gkr_wire: &GkrProofWire, + batch_wire: &BatchConstraintProofWire, + n_per_trace: &[isize], + trace_id_to_air_id: &[usize], + public_values: Vec>, + profiler: &mut CellProfiler, +) -> BatchConstraintIntermediatesWire { + let l_skip = mvk0.params.l_skip; + + let trace_id_to_air_id_host = trace_id_to_air_id.to_vec(); + let total_interactions_host = zip(trace_id_to_air_id, n_per_trace) + .map(|(&air_idx, &n)| { + let n_lift = n.max(0) as usize; + let num_interactions = mvk0.per_air[air_idx] + .symbolic_constraints + .interactions + .len(); + (num_interactions as u64) << (l_skip + n_lift) + }) + .sum::(); + assert!(total_interactions_host > 0, "0 interactions not supported"); + let n_logup_host = calculate_n_logup(l_skip, total_interactions_host); + let n_max_host = n_per_trace.iter().copied().max().unwrap().max(0) as usize; + let n_global_host = n_max_host.max(n_logup_host); + let omega_skip = RootF::two_adic_generator(l_skip); + let omega_skip_pows: Vec<_> = omega_skip.powers().take(1usize << l_skip).collect(); + + let trace_has_preprocessed = trace_id_to_air_id + .iter() + .map(|&air_id| mvk0.per_air[air_id].preprocessed_data.is_some()) + .collect::>(); + let trace_constraint_nodes = trace_id_to_air_id + .iter() + .map(|&air_id| { + mvk0.per_air[air_id] + .symbolic_constraints + .constraints + .nodes + .clone() + }) + .collect::>(); + let trace_constraint_indices = trace_id_to_air_id + .iter() + .map(|&air_id| { + mvk0.per_air[air_id] + .symbolic_constraints + .constraints + .constraint_idx + .clone() + }) + .collect::>(); + let trace_interactions = trace_id_to_air_id + .iter() + .map(|&air_id| { + mvk0.per_air[air_id] + .symbolic_constraints + .interactions + .clone() + }) + .collect::>(); + let column_openings_need_rot = trace_id_to_air_id + .iter() + .map(|&air_id| { + let need_rot = mvk0.per_air[air_id].params.need_rot; + vec![need_rot; mvk0.per_air[air_id].num_parts()] + }) + .collect::>(); + + let logup_pow_bits = mvk0.params.logup.pow_bits; + let logup_pow_witness = gkr_wire.logup_pow_witness; + transcript.check_witness(ctx, logup_pow_bits, &logup_pow_witness); + + let alpha_logup = transcript.sample_ext(ctx); + let beta_logup = transcript.sample_ext(ctx); + + profiler.push("gkr_verification", ctx.advice.len()); + + let gkr_claims_per_layer = &gkr_wire.claims_per_layer; + let gkr_sumcheck_polys = &gkr_wire.sumcheck_polys; + + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let total_gkr_rounds = l_skip + n_logup_host; + let (mut gkr_p_xi_claim, mut gkr_q_xi_claim, mut xi) = { + let gkr_q0_claim = gkr_wire.q0_claim; + transcript.observe_ext(ctx, &gkr_q0_claim); + + let layer0 = &gkr_claims_per_layer[0]; + observe_layer_claims_assigned(ctx, transcript, layer0); + + let layer0_p0 = layer0[0].into(); + let layer0_q0 = layer0[1].into(); + let layer0_p1 = layer0[2].into(); + let layer0_q1 = layer0[3].into(); + let p0_q1 = ext_chip.mul(ctx, layer0_p0, layer0_q1); + let p1_q0 = ext_chip.mul(ctx, layer0_p1, layer0_q0); + let p_cross = ext_chip.add(ctx, p0_q1, p1_q0); + let q_cross = ext_chip.mul(ctx, layer0_q0, layer0_q1); + ext_chip.assert_zero(ctx, p_cross); + ext_chip.assert_equal(ctx, q_cross, gkr_q0_claim.into()); + + let mu0 = transcript.sample_ext(ctx); + let mut numer_claim = + interpolate_linear_at_01_assigned(ctx, ext_chip, &layer0_p0, &layer0_p1, &mu0); + let mut denom_claim = + interpolate_linear_at_01_assigned(ctx, ext_chip, &layer0_q0, &layer0_q1, &mu0); + let mut gkr_r = vec![mu0]; + + for round in 1..total_gkr_rounds { + let lambda_round = transcript.sample_ext(ctx); + + let lambda_denom = ext_chip.mul(ctx, lambda_round, denom_claim); + let mut claim = ext_chip.add(ctx, numer_claim, lambda_denom); + let round_polys = &gkr_sumcheck_polys[round - 1]; + let mut gkr_r_prime = Vec::with_capacity(round); + let mut eq = one; + + for (subround, xi_prev) in gkr_r.iter().enumerate().take(round) { + let [ev1, ev2, ev3] = round_polys[subround]; + transcript.observe_ext(ctx, &ev1); + transcript.observe_ext(ctx, &ev2); + transcript.observe_ext(ctx, &ev3); + + let ri = transcript.sample_ext(ctx); + gkr_r_prime.push(ri); + + let ev1 = ev1.into(); + let ev2 = ev2.into(); + let ev3 = ev3.into(); + let ev0 = ext_chip.sub(ctx, claim, ev1); + claim = interpolate_cubic_at_0123_assigned( + ctx, + ext_chip, + [&ev0, &ev1, &ev2, &ev3], + &ri, + ); + let xi_ri = ext_chip.mul(ctx, *xi_prev, ri); + let one_minus_xi = ext_chip.sub(ctx, one, *xi_prev); + let one_minus_ri = ext_chip.sub(ctx, one, ri); + let one_minus_term = ext_chip.mul(ctx, one_minus_xi, one_minus_ri); + let eq_factor = ext_chip.add(ctx, xi_ri, one_minus_term); + eq = ext_chip.mul(ctx, eq, eq_factor); + } + + let layer_claims = &gkr_claims_per_layer[round]; + observe_layer_claims_assigned(ctx, transcript, layer_claims); + + let layer_p0 = layer_claims[0].into(); + let layer_q0 = layer_claims[1].into(); + let layer_p1 = layer_claims[2].into(); + let layer_q1 = layer_claims[3].into(); + let p0_q1 = ext_chip.mul(ctx, layer_p0, layer_q1); + let p1_q0 = ext_chip.mul(ctx, layer_p1, layer_q0); + let p_cross = ext_chip.add(ctx, p0_q1, p1_q0); + let q_cross = ext_chip.mul(ctx, layer_q0, layer_q1); + let lambda_q_cross = ext_chip.mul(ctx, lambda_round, q_cross); + let claim_sum = ext_chip.add(ctx, p_cross, lambda_q_cross); + let expected_claim = ext_chip.mul(ctx, claim_sum, eq); + ext_chip.assert_equal(ctx, expected_claim, claim); + + let mu_round = transcript.sample_ext(ctx); + numer_claim = + interpolate_linear_at_01_assigned(ctx, ext_chip, &layer_p0, &layer_p1, &mu_round); + denom_claim = + interpolate_linear_at_01_assigned(ctx, ext_chip, &layer_q0, &layer_q1, &mu_round); + gkr_r = core::iter::once(mu_round) + .chain(gkr_r_prime.into_iter()) + .collect(); + } + + (numer_claim, denom_claim, gkr_r) + }; + + while xi.len() != l_skip + n_global_host { + xi.push(transcript.sample_ext(ctx)); + } + + let lambda = transcript.sample_ext(ctx); + + profiler.pop(ctx.advice.len()); + profiler.push("batch_sumcheck", ctx.advice.len()); + + let numerator_term_per_air = &batch_wire.numerator_term_per_air; + let denominator_term_per_air = &batch_wire.denominator_term_per_air; + for (num_term, den_term) in numerator_term_per_air + .iter() + .zip(denominator_term_per_air.iter()) + { + gkr_p_xi_claim = ext_chip.sub(ctx, gkr_p_xi_claim, num_term.into()); + gkr_q_xi_claim = ext_chip.sub(ctx, gkr_q_xi_claim, den_term.into()); + transcript.observe_ext(ctx, num_term); + transcript.observe_ext(ctx, den_term); + } + let gkr_numerator_residual = gkr_p_xi_claim; + let gkr_denominator_claim = gkr_q_xi_claim; + ext_chip.assert_zero(ctx, gkr_numerator_residual); + ext_chip.assert_equal(ctx, gkr_denominator_claim, alpha_logup); + + let mu = transcript.sample_ext(ctx); + + let mut sum_claim = ext_chip.zero(ctx); + let mut cur_mu_pow = one; + let mut first_mu_term = true; + for (num_term, den_term) in numerator_term_per_air + .iter() + .zip(denominator_term_per_air.iter()) + { + let num_term = num_term.into(); + let den_term = den_term.into(); + let num_weighted = if first_mu_term { + first_mu_term = false; + num_term + } else { + ext_chip.mul(ctx, num_term, cur_mu_pow) + }; + sum_claim = ext_chip.add(ctx, sum_claim, num_weighted); + cur_mu_pow = ext_chip.mul(ctx, cur_mu_pow, mu); + + let den_weighted = ext_chip.mul(ctx, den_term, cur_mu_pow); + sum_claim = ext_chip.add(ctx, sum_claim, den_weighted); + cur_mu_pow = ext_chip.mul(ctx, cur_mu_pow, mu); + } + + let univariate_round_coeffs = &batch_wire.univariate_round_coeffs; + for coeff in univariate_round_coeffs { + transcript.observe_ext(ctx, coeff); + } + let univariate_round_coeffs_raw = univariate_round_coeffs + .iter() + .map(|coeff| coeff.into()) + .collect::>(); + let mut r = vec![transcript.sample_ext(ctx)]; + + let stride = 1usize << l_skip; + let mut sum_univ_domain_s_0 = ext_chip.zero(ctx); + for coeff in univariate_round_coeffs_raw.iter().step_by(stride) { + sum_univ_domain_s_0 = ext_chip.add(ctx, sum_univ_domain_s_0, *coeff); + } + let sum_univ_domain_s_0 = + ext_chip.mul_base_const(ctx, sum_univ_domain_s_0, RootF::from_u64(stride as u64)); + ext_chip.assert_equal(ctx, sum_claim, sum_univ_domain_s_0); + + let sumcheck_round_polys = &batch_wire.sumcheck_round_polys; + let mut consistency_lhs = + horner_eval_ext_poly_assigned(ctx, ext_chip, &univariate_round_coeffs_raw, &r[0]); + for round_evals in sumcheck_round_polys { + for eval in round_evals { + transcript.observe_ext(ctx, eval); + } + + let s_1 = round_evals[0].into(); + let s_0 = ext_chip.sub(ctx, consistency_lhs, s_1); + let mut interpolation_evals = Vec::with_capacity(round_evals.len() + 1); + interpolation_evals.push(s_0); + interpolation_evals.extend(round_evals.iter().map(BabyBearExtWire::from)); + let next_r = transcript.sample_ext(ctx); + consistency_lhs = + eval_lagrange_on_integer_grid(ctx, ext_chip, &next_r, &interpolation_evals); + r.push(next_r); + } + + profiler.pop(ctx.advice.len()); + profiler.push("observe_openings", ctx.advice.len()); + + let column_openings = &batch_wire.column_openings; + + let reduced_zero = ext_chip.load_reduced_constant(ctx, RootEF::ZERO); + for (trace_idx, air_openings) in column_openings.iter().enumerate() { + let need_rot = column_openings_need_rot[trace_idx][0]; + let openings = &air_openings[0]; + if need_rot { + assert!( + openings.len().is_multiple_of(2), + "rotated opening vector must be even", + ); + for claim in openings.chunks_exact(2) { + transcript.observe_ext(ctx, &claim[0]); + transcript.observe_ext(ctx, &claim[1]); + } + } else { + for opening in openings { + transcript.observe_ext(ctx, opening); + transcript.observe_ext(ctx, &reduced_zero); + } + } + } + + for (trace_idx, air_openings) in column_openings.iter().enumerate() { + for (part_idx, claims) in air_openings.iter().enumerate().skip(1) { + let need_rot = column_openings_need_rot[trace_idx][part_idx]; + if need_rot { + assert!( + claims.len().is_multiple_of(2), + "rotated opening vector must be even", + ); + for claim in claims.chunks_exact(2) { + transcript.observe_ext(ctx, &claim[0]); + transcript.observe_ext(ctx, &claim[1]); + } + } else { + for claim in claims { + transcript.observe_ext(ctx, claim); + transcript.observe_ext(ctx, &reduced_zero); + } + } + } + } + + profiler.pop(ctx.advice.len()); + profiler.push("eq_3b_tree", ctx.advice.len()); + + let mut eq_3b_per_trace = Vec::with_capacity(n_per_trace.len()); + let mut stacked_idx = 0usize; + for (trace_idx, &n) in n_per_trace.iter().enumerate() { + let n_lift = n.max(0) as usize; + let interactions = &trace_interactions[trace_idx]; + if interactions.is_empty() { + eq_3b_per_trace.push(Vec::new()); + continue; + } + + let d = n_logup_host.saturating_sub(n_lift); + let xi_slice = &xi[l_skip + n_lift..l_skip + n_logup_host]; + + // Determine needed leaf indices before building the tree. + let needed_leaves: Vec = { + let mut leaves = Vec::with_capacity(interactions.len()); + let mut tmp_idx = stacked_idx; + for _ in 0..interactions.len() { + let b_int = tmp_idx >> (l_skip + n_lift); + let tree_idx = b_int & ((1 << d) - 1); + leaves.push(tree_idx); + tmp_idx += 1 << (l_skip + n_lift); + } + leaves + }; + + // Precompute per-bit factors: (x_i, 1-x_i) for tree product. + let factors: Vec<(BabyBearExtWire, BabyBearExtWire)> = xi_slice + .iter() + .map(|x_i| { + let one_minus_x = ext_chip.sub(ctx, one, *x_i); + (*x_i, one_minus_x) + }) + .collect(); + + // Build a sparse partial product tree containing only ancestors of needed leaves. + // tree[level][node_idx] = product of factors for bits matching node_idx. + // Level 0: single root node with value `one`. + // Level j+1: only children whose index appears in the needed set for that level. + let mut prev_level: BTreeMap = BTreeMap::new(); + prev_level.insert(0, one); + + for level_idx in 0..d { + let factor_j = d - 1 - level_idx; + // Determine which nodes are needed at level (level_idx + 1): + // a leaf index shifted right by the remaining levels. + let shift = d - (level_idx + 1); + let mut curr_level = BTreeMap::new(); + for node_idx in needed_leaves.iter().map(|&leaf| leaf >> shift) { + if curr_level.contains_key(&node_idx) { + continue; + } + let parent_idx = node_idx >> 1; + let parent = prev_level[&parent_idx]; + let val = if node_idx & 1 == 0 { + ext_chip.mul(ctx, parent, factors[factor_j].1) + } else { + ext_chip.mul(ctx, parent, factors[factor_j].0) + }; + curr_level.insert(node_idx, val); + } + prev_level = curr_level; + } + + // Look up each interaction's eq_3b from the sparse tree leaves. + let mut eq_3b = Vec::with_capacity(interactions.len()); + for &tree_idx in &needed_leaves { + stacked_idx += 1 << (l_skip + n_lift); + eq_3b.push(prev_level[&tree_idx]); + } + eq_3b_per_trace.push(eq_3b); + } + + profiler.pop(ctx.advice.len()); + profiler.push("eq_ns_precompute", ctx.advice.len()); + + let mut eq_ns = vec![one; n_max_host + 1]; + let mut eq_sharp_ns = vec![one; n_max_host + 1]; + eq_ns[0] = eval_eq_uni_assigned(ctx, ext_chip, l_skip, &xi[0], &r[0]); + eq_sharp_ns[0] = + eval_eq_sharp_uni_assigned(ctx, ext_chip, &omega_skip_pows, &xi[..l_skip], &r[0]); + for (i, r_i) in r.iter().enumerate().skip(1) { + let eq_mle = eval_eq_mle_assigned( + ctx, + ext_chip, + &[xi[l_skip + i - 1]], + core::slice::from_ref(r_i), + ); + eq_ns[i] = ext_chip.mul(ctx, eq_ns[i - 1], eq_mle); + eq_sharp_ns[i] = ext_chip.mul(ctx, eq_sharp_ns[i - 1], eq_mle); + eq_ns[i] = ext_chip.reduce_max_bits(ctx, eq_ns[i]); + eq_sharp_ns[i] = ext_chip.reduce_max_bits(ctx, eq_sharp_ns[i]); + } + if n_max_host > 0 { + let n_max_usize = n_max_host; + let mut r_rev_prod = r[n_max_usize]; + for i in (0..n_max_usize).rev() { + eq_ns[i] = ext_chip.mul(ctx, eq_ns[i], r_rev_prod); + eq_sharp_ns[i] = ext_chip.mul(ctx, eq_sharp_ns[i], r_rev_prod); + eq_ns[i] = ext_chip.reduce_max_bits(ctx, eq_ns[i]); + eq_sharp_ns[i] = ext_chip.reduce_max_bits(ctx, eq_sharp_ns[i]); + r_rev_prod = ext_chip.mul(ctx, r_rev_prod, r[i]); + } + } + + profiler.pop(ctx.advice.len()); + profiler.push("constraint_eval", ctx.advice.len()); + + let mut interactions_evals = Vec::new(); + let mut constraints_evals = Vec::new(); + + let mut beta_pows = vec![one]; + let mut lambda_pows = vec![one]; + for (trace_idx, air_openings) in column_openings.iter().enumerate() { + let air_idx = trace_id_to_air_id_host[trace_idx]; + let n = n_per_trace[trace_idx]; + let n_lift = n.max(0) as usize; + + let need_rot_flags = &column_openings_need_rot[trace_idx]; + let common_main = + local_next_opening_views(ctx, ext_chip, &air_openings[0], need_rot_flags[0]); + let has_preprocessed = trace_has_preprocessed[trace_idx]; + let preprocessed = has_preprocessed + .then(|| local_next_opening_views(ctx, ext_chip, &air_openings[1], need_rot_flags[1])); + let cached_idx = 1 + has_preprocessed as usize; + let mut partitioned_main = air_openings[cached_idx..] + .iter() + .enumerate() + .map(|(part_offset, opening)| { + local_next_opening_views( + ctx, + ext_chip, + opening, + need_rot_flags[cached_idx + part_offset], + ) + }) + .collect::>(); + partitioned_main.push(common_main); + + let (l, rs_n, norm_factor) = if n.is_negative() { + ( + l_skip.wrapping_add_signed(n), + vec![ext_chip.pow_power_of_two(ctx, r[0], n.unsigned_abs())], + RootF::from_usize(1usize << n.unsigned_abs()).inverse(), + ) + } else { + (l_skip, r[..=n_lift].to_vec(), RootF::ONE) + }; + + let inv_l = RootF::from_usize(1usize << l).inverse(); + let mut is_first_row = progression_exp_2_assigned(ctx, ext_chip, &rs_n[0], l); + is_first_row = ext_chip.mul_base_const(ctx, is_first_row, inv_l); + for x in rs_n.iter().skip(1) { + let one_minus_x = ext_chip.sub(ctx, one, *x); + is_first_row = ext_chip.mul(ctx, is_first_row, one_minus_x); + } + + let omega = RootF::two_adic_generator(l); + let rs0_omega = ext_chip.mul_base_const(ctx, rs_n[0], omega); + let mut is_last_row = progression_exp_2_assigned(ctx, ext_chip, &rs0_omega, l); + is_last_row = ext_chip.mul_base_const(ctx, is_last_row, inv_l); + for x in rs_n.iter().skip(1) { + is_last_row = ext_chip.mul(ctx, is_last_row, *x); + } + + let evaluator = ConstraintEvaluatorWire { + preprocessed: preprocessed.as_deref(), + partitioned_main: &partitioned_main, + is_first_row: ext_chip.reduce_max_bits(ctx, is_first_row), + is_last_row: ext_chip.reduce_max_bits(ctx, is_last_row), + public_values: public_values[air_idx].as_slice(), + }; + + let node_values = eval_symbolic_nodes_assigned( + ctx, + ext_chip, + &evaluator, + &trace_constraint_nodes[trace_idx], + ); + + let mut expr = ext_chip.zero(ctx); + for (i, &constraint_idx) in trace_constraint_indices[trace_idx].iter().enumerate() { + let term = if i == 0 { + node_values[constraint_idx] + } else { + if i >= lambda_pows.len() { + debug_assert_eq!(i, lambda_pows.len()); + let new_pow = ext_chip.mul(ctx, *lambda_pows.last().unwrap(), lambda); + lambda_pows.push(ext_chip.reduce_max_bits(ctx, new_pow)); + } + + ext_chip.mul(ctx, node_values[constraint_idx], lambda_pows[i]) + }; + expr = ext_chip.add(ctx, expr, term); + } + constraints_evals.push(ext_chip.mul(ctx, eq_ns[n_lift], expr)); + + let interactions = &trace_interactions[trace_idx]; + let eq_3bs = &eq_3b_per_trace[trace_idx]; + let mut num = ext_chip.zero(ctx); + let mut denom = ext_chip.zero(ctx); + for (eq_3b, interaction) in eq_3bs.iter().zip(interactions.iter()) { + let count_eval = node_values[interaction.count]; + let mut denom_eval = ext_chip.zero(ctx); + for (j, &msg_idx) in interaction.message.iter().enumerate() { + let term = if j == 0 { + node_values[msg_idx] + } else { + if j >= beta_pows.len() { + debug_assert_eq!(j, beta_pows.len()); + let new_pow = ext_chip.mul(ctx, *beta_pows.last().unwrap(), beta_logup); + beta_pows.push(ext_chip.reduce_max_bits(ctx, new_pow)); + } + + ext_chip.mul(ctx, node_values[msg_idx], beta_pows[j]) + }; + denom_eval = ext_chip.add(ctx, denom_eval, term); + } + if interaction.message.len() >= beta_pows.len() { + let new_pow = ext_chip.mul(ctx, *beta_pows.last().unwrap(), beta_logup); + beta_pows.push(ext_chip.reduce_max_bits(ctx, new_pow)); + } + let bus_term = ext_chip.mul_base_const( + ctx, + beta_pows[interaction.message.len()], + RootF::from_u64(u64::from(interaction.bus_index) + 1), + ); + denom_eval = ext_chip.add(ctx, denom_eval, bus_term); + + let eq_times_count = ext_chip.mul(ctx, *eq_3b, count_eval); + num = ext_chip.add(ctx, num, eq_times_count); + let eq_times_denom = ext_chip.mul(ctx, *eq_3b, denom_eval); + denom = ext_chip.add(ctx, denom, eq_times_denom); + } + + let num_norm = if norm_factor == RootF::ONE { + num + } else { + ext_chip.mul_base_const(ctx, num, norm_factor) + }; + let num_scaled = ext_chip.mul(ctx, num_norm, eq_sharp_ns[n_lift]); + let denom_scaled = ext_chip.mul(ctx, denom, eq_sharp_ns[n_lift]); + interactions_evals.push(num_scaled); + interactions_evals.push(denom_scaled); + } + + profiler.pop(ctx.advice.len()); + profiler.push("final_consistency", ctx.advice.len()); + + let mut consistency_rhs = ext_chip.zero(ctx); + let mut cur_mu_pow = one; + for (i, term) in interactions_evals + .iter() + .chain(constraints_evals.iter()) + .enumerate() + { + let weighted_term = if i == 0 { + *term + } else { + ext_chip.mul(ctx, *term, cur_mu_pow) + }; + consistency_rhs = ext_chip.add(ctx, consistency_rhs, weighted_term); + cur_mu_pow = ext_chip.mul(ctx, cur_mu_pow, mu); + } + ext_chip.assert_equal(ctx, consistency_lhs, consistency_rhs); + + profiler.pop(ctx.advice.len()); + + BatchConstraintIntermediatesWire { + column_openings: column_openings.clone(), + r, + } +} diff --git a/patches/openvm-static-verifier/src/stages/full_pipeline/mod.rs b/patches/openvm-static-verifier/src/stages/full_pipeline/mod.rs new file mode 100644 index 00000000..baf9bedb --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/full_pipeline/mod.rs @@ -0,0 +1,321 @@ +use halo2_base::{utils::biguint_to_fe, AssignedValue, Context}; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::{BabyBearBn254Poseidon2Config as RootConfig, Bn254Scalar}, + openvm_stark_backend::{ + keygen::types::{MultiStarkVerifyingKey, MultiStarkVerifyingKey0}, + p3_field::{PrimeCharacteristicRing, PrimeField}, + proof::Proof, + prover::stacked_pcs::StackedLayout, + }, + p3_baby_bear::BabyBear, +}; + +use crate::{ + field::baby_bear::{BabyBearExtChip, ReducedBabyBearWire}, + stages::{ + batch_constraints::{ + constrain_batch_constraints_verification, load_batch_constraint_proof_wire, + load_gkr_proof_wire, BatchConstraintProofWire, GkrProofWire, + }, + proof_shape::log_heights_per_air_from_proof, + stacked_reduction::{ + constrain_stacked_reduction, load_stacking_proof_wire, StackingProofWire, + }, + whir::{constrain_whir_verification, load_whir_proof_wire, WhirProofWire}, + }, + transcript::{digest_wire_from_root, DigestWire, TranscriptChip}, + Fr, +}; + +mod public_values; +#[cfg(test)] +mod tests; + +pub use public_values::*; + +#[derive(Clone, Debug)] +pub struct ProofWire { + pub common_main_commit_root: AssignedValue, + pub public_values: Vec>, + pub cached_commitment_roots: Vec>>, + pub gkr: GkrProofWire, + pub batch: BatchConstraintProofWire, + pub stacking: StackingProofWire, + pub whir: WhirProofWire, +} + +pub(crate) fn digest_scalar_to_fr(value: Bn254Scalar) -> Fr { + biguint_to_fe(&value.as_canonical_biguint()) +} + +/// Load proof data into Halo2 cells. `log_heights_per_air` must match this circuit's fixed heights; +/// host-side asserts that per-AIR log heights extracted from the proof match `log_heights_per_air`. +pub fn load_proof_wire( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + proof: &Proof, + log_heights_per_air: &[usize], +) -> ProofWire { + let from_proof = log_heights_per_air_from_proof(proof); + assert_eq!( + from_proof.as_slice(), + log_heights_per_air, + "per-AIR log heights from proof must match this circuit's fixed log_heights_per_air" + ); + + let base_chip = ext_chip.base(); + + let common_main_commit_root = + ctx.load_witness(digest_scalar_to_fr(proof.common_main_commit[0])); + + let public_values = proof + .public_values + .iter() + .map(|values| { + values + .iter() + .map(|&value| base_chip.load_reduced_witness(ctx, value)) + .collect() + }) + .collect(); + + let cached_commitment_roots = proof + .trace_vdata + .iter() + .map(|vdata| { + if let Some(vdata) = vdata { + vdata + .cached_commitments + .iter() + .map(|commit| ctx.load_witness(digest_scalar_to_fr(commit[0]))) + .collect() + } else { + Vec::new() + } + }) + .collect(); + + let gkr = load_gkr_proof_wire(ctx, base_chip, ext_chip, &proof.gkr_proof); + let batch = load_batch_constraint_proof_wire(ctx, ext_chip, &proof.batch_constraint_proof); + let stacking = load_stacking_proof_wire(ctx, ext_chip, &proof.stacking_proof); + let whir = load_whir_proof_wire(ctx, base_chip, ext_chip, &proof.whir_proof); + + ProofWire { + common_main_commit_root, + public_values, + cached_commitment_roots, + gkr, + batch, + stacking, + whir, + } +} + +#[allow(clippy::too_many_arguments)] +fn observe_preamble( + ctx: &mut Context, + transcript: &mut TranscriptChip, + mvk: &MultiStarkVerifyingKey, + log_heights_per_air: &[usize], + public_values: &[Vec], + cached_commitment_roots: &[Vec>], + vk_pre_hash: DigestWire, + common_main_commit: DigestWire, +) { + transcript.observe_commit(ctx, &vk_pre_hash); + transcript.observe_commit(ctx, &common_main_commit); + + for air_idx in 0..mvk.inner.per_air.len() { + if !mvk.inner.per_air[air_idx].is_required { + // Static verifier: every AIR in the child VK has a trace (see crate `lib.rs`). + let presence_flag = transcript + .baby_bear() + .load_reduced_constant(ctx, BabyBear::ONE); + transcript.observe(ctx, &presence_flag); + } + + if let Some(preprocessed) = mvk.inner.per_air[air_idx].preprocessed_data.as_ref() { + let preprocessed_root = ctx.load_constant(digest_scalar_to_fr(preprocessed.commit[0])); + transcript.observe_commit(ctx, &digest_wire_from_root(preprocessed_root)); + } else { + // Fixed circuit parameter (not loaded from the proof witness). + let lh = u32::try_from(log_heights_per_air[air_idx]) + .expect("log_height must fit in u32 for BabyBear constant"); + let log_height = transcript + .baby_bear() + .load_reduced_constant(ctx, BabyBear::from_u32(lh)); + transcript.observe(ctx, &log_height); + } + + for root in &cached_commitment_roots[air_idx] { + transcript.observe_commit(ctx, &digest_wire_from_root(*root)); + } + + for value in &public_values[air_idx] { + transcript.observe(ctx, value); + } + } +} + +/// Run the full static verifier pipeline on pre-loaded witness data. +/// +/// `trace_id_to_air_id` and `log_heights_per_air` are fixed for this circuit (host-side). They must +/// match the child proof shape: `log_heights_per_air.len() == mvk.inner.per_air.len()`, and +/// `trace_id_to_air_id` must list every `air_id` exactly once in descending-`log_height` order +/// (tie-break: ascending `air_id`). +/// +/// `stacked_layouts` must be the layout vector fixed for this circuit (same as stored on +/// [`crate::StaticVerifierCircuit`]). +/// +/// Returns the two statement public inputs as assigned cells: +/// `[mvk_pre_hash_root, common_main_commit_root]`. +pub fn constrained_verify( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + root_vk: &MultiStarkVerifyingKey, + proof_wire: &ProofWire, /* Root proof */ + trace_id_to_air_id: &[usize], + log_heights_per_air: &[usize], + stacked_layouts: &[StackedLayout], +) { + assert_eq!( + log_heights_per_air.len(), + root_vk.inner.per_air.len(), + "log_heights_per_air must match VK per_air count" + ); + let l_skip = root_vk.inner.params.l_skip; + let n_per_trace: Vec = trace_id_to_air_id + .iter() + .map(|&air_id| log_heights_per_air[air_id] as isize - l_skip as isize) + .collect(); + + let mut profiler = crate::profiling::CellProfiler::new("constrained_verify", ctx.advice.len()); + + let mvk_pre_hash_root = ctx.load_constant(digest_scalar_to_fr(root_vk.pre_hash[0])); + let mut transcript = TranscriptChip::new(ctx, ext_chip.base().clone()); + + profiler.push("observe_preamble", ctx.advice.len()); + observe_preamble( + ctx, + &mut transcript, + root_vk, + log_heights_per_air, + &proof_wire.public_values, + &proof_wire.cached_commitment_roots, + digest_wire_from_root(mvk_pre_hash_root), + digest_wire_from_root(proof_wire.common_main_commit_root), + ); + profiler.pop(ctx.advice.len()); + + profiler.push("batch_constraints", ctx.advice.len()); + let batch = constrain_batch_constraints_verification( + ctx, + ext_chip, + &mut transcript, + &root_vk.inner, + &proof_wire.gkr, + &proof_wire.batch, + &n_per_trace, + trace_id_to_air_id, + proof_wire.public_values.clone(), + &mut profiler, + ); + profiler.pop(ctx.advice.len()); + + let need_rot_per_commit = get_need_rot_per_commit(&root_vk.inner, trace_id_to_air_id); + + profiler.push("stacked_reduction", ctx.advice.len()); + let stacked_reduction = constrain_stacked_reduction( + ctx, + ext_chip, + &mut transcript, + &proof_wire.stacking, + stacked_layouts, + &need_rot_per_commit, + l_skip, + root_vk.inner.params.n_stack, + &batch.column_openings, + &batch.r, + &mut profiler, + ); + profiler.pop(ctx.advice.len()); + + let u_cube = { + let u = &stacked_reduction.u; + assert!(!u.is_empty()); + let mut u_cube = Vec::with_capacity(l_skip + u.len().saturating_sub(1)); + let mut power = *u.first().unwrap(); + for _ in 0..l_skip { + u_cube.push(power); + power = ext_chip.square(ctx, power); + power = ext_chip.reduce_max_bits(ctx, power); + } + u_cube.extend(u.iter().skip(1).copied()); + u_cube + }; + + let initial_commitment_roots = { + let common_main_root = proof_wire.common_main_commit_root; + let mut commits = vec![common_main_root]; + for &air_id in trace_id_to_air_id { + if let Some(preprocessed) = &root_vk.inner.per_air[air_id].preprocessed_data { + commits.push(ctx.load_constant(digest_scalar_to_fr(preprocessed.commit[0]))); + } + commits.extend(proof_wire.cached_commitment_roots[air_id].iter().copied()); + } + commits + }; + + profiler.push("whir_verification", ctx.advice.len()); + constrain_whir_verification( + ctx, + ext_chip, + &mut transcript, + &root_vk.inner, + &proof_wire.whir, + &stacked_reduction.stacking_openings, + &initial_commitment_roots, + &u_cube, + &mut profiler, + ); + profiler.pop(ctx.advice.len()); + + profiler.print(ctx.advice.len()); + + #[cfg(feature = "cell-profiling")] + if let Ok(dir) = std::env::var("OPENVM_PROFILE_DIR") { + let _ = std::fs::create_dir_all(&dir); + profiler.write_flamegraph( + &format!("{dir}/constrained_verify.svg"), + "Constrained Verify Sub-stages", + ctx.advice.len(), + ); + profiler.write_flamegraph_reversed( + &format!("{dir}/constrained_verify_rev.svg"), + "Constrained Verify Sub-stages (reversed)", + ctx.advice.len(), + ); + } +} + +/// Helper function, purely on out-of-circuit values. +fn get_need_rot_per_commit( + mvk0: &MultiStarkVerifyingKey0, + trace_id_to_air_id: &[usize], +) -> Vec> { + let mut need_rot_per_commit = vec![trace_id_to_air_id + .iter() + .map(|&air_id| mvk0.per_air[air_id].params.need_rot) + .collect::>()]; + for &air_id in trace_id_to_air_id { + let need_rot = mvk0.per_air[air_id].params.need_rot; + if mvk0.per_air[air_id].preprocessed_data.is_some() { + need_rot_per_commit.push(vec![need_rot]); + } + let cached_len = mvk0.per_air[air_id].params.width.cached_mains.len(); + for _ in 0..cached_len { + need_rot_per_commit.push(vec![need_rot]); + } + } + need_rot_per_commit +} diff --git a/patches/openvm-static-verifier/src/stages/full_pipeline/public_values.rs b/patches/openvm-static-verifier/src/stages/full_pipeline/public_values.rs new file mode 100644 index 00000000..768473bc --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/full_pipeline/public_values.rs @@ -0,0 +1,84 @@ +use std::borrow::Borrow; + +use halo2_base::{ + gates::GateInstructions, halo2_proofs::arithmetic::Field, AssignedValue, Context, QuantumCell, +}; +use openvm_continuations::circuit::root::{RootVerifierPvs, USER_PVS_COMMIT_AIR_ID}; +use openvm_stark_sdk::config::baby_bear_poseidon2::DIGEST_SIZE as APP_DIGEST_SIZE; +use openvm_verify_stark_host::pvs::VERIFIER_PVS_AIR_ID; + +use crate::{ + field::baby_bear::{BabyBearChip, ReducedBabyBearWire, BABY_BEAR_MODULUS_U64}, + stages::full_pipeline::ProofWire, + Fr, +}; + +#[repr(C)] +pub struct StaticVerifierPvs { + /// Hashed combination of the app-level ProgramAir cached trace, the Merkle root commit of + /// the starting app memory state (i.e. initial_root), and the initial app program counter + /// (i.e. initial_pc). + pub app_exe_commit: T, + /// Commit to the app-level verifying key, computed by hashing the cached_commit and + /// vk_pre_hash components of the app, leaf, and internal-for-leaf vk commits. + pub app_vm_commit: T, + /// The number of user public values is a configuration parameter in the App VM. This parameter + /// is treated as a constant in the static verifier circuit. + pub user_public_values: Vec, +} + +impl StaticVerifierPvs { + pub fn to_vec(&self) -> Vec { + let mut vec = vec![self.app_exe_commit.clone(), self.app_vm_commit.clone()]; + vec.extend_from_slice(&self.user_public_values); + vec + } + + pub fn from_slice(slice: &[T]) -> Self { + Self { + app_exe_commit: slice[0].clone(), + app_vm_commit: slice[1].clone(), + user_public_values: slice[2..].to_vec(), + } + } +} + +/// Extracts the public values from the root proof and returns them. These public values will be +/// re-exposed as public values of the static verifier circuit, but that is **not** done in this +/// function. +pub fn extract_public_values( + ctx: &mut Context, + chip: &BabyBearChip, + proof: &ProofWire, +) -> StaticVerifierPvs> { + let root_pvs: &RootVerifierPvs = + proof.public_values[VERIFIER_PVS_AIR_ID].as_slice().borrow(); + let app_exe_commit = compress_babybear_wires_to_bn254(ctx, chip, root_pvs.app_exe_commit); + let app_vm_commit = compress_babybear_wires_to_bn254(ctx, chip, root_pvs.app_vm_commit); + let user_pvs = &proof.public_values[USER_PVS_COMMIT_AIR_ID]; + let user_public_values = user_pvs.iter().map(|bb| bb.value()).collect::>(); + + StaticVerifierPvs { + app_exe_commit, + app_vm_commit, + user_public_values, + } +} + +pub fn compress_babybear_wires_to_bn254( + ctx: &mut Context, + chip: &BabyBearChip, + base_elts: [ReducedBabyBearWire; APP_DIGEST_SIZE], +) -> AssignedValue { + let reduced_elts = base_elts.map(|bb| bb.value()); + let order = Fr::from(BABY_BEAR_MODULUS_U64); + let mut bases = [Fr::ONE; APP_DIGEST_SIZE]; + for i in 1..APP_DIGEST_SIZE { + bases[i] = bases[i - 1] * order; + } + chip.gate().inner_product( + ctx, + reduced_elts, + bases.into_iter().map(QuantumCell::Constant), + ) +} diff --git a/patches/openvm-static-verifier/src/stages/full_pipeline/tests.rs b/patches/openvm-static-verifier/src/stages/full_pipeline/tests.rs new file mode 100644 index 00000000..d2e5c9c8 --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/full_pipeline/tests.rs @@ -0,0 +1,267 @@ +use std::sync::Arc; + +use halo2_base::{ + gates::circuit::{builder::BaseCircuitBuilder, CircuitBuilderStage}, + halo2_proofs::dev::MockProver, +}; +use itertools::Itertools; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::{ + BabyBearBn254Poseidon2Config as RootConfig, BabyBearBn254Poseidon2CpuEngine, + }, + openvm_stark_backend::{ + p3_field::{PrimeCharacteristicRing, PrimeField64, TwoAdicField}, + test_utils::{ + test_system_params_small, CachedFixture11, InteractionsFixture11, MixtureFixture, + TestFixture, + }, + StarkEngine, + }, +}; + +use super::*; +use crate::{ + circuit::build_stacked_layouts_for_static_vk, + config::{STATIC_VERIFIER_LOOKUP_ADVICE_COLS, STATIC_VERIFIER_NUM_ADVICE_COLS}, + field::baby_bear::{ + clear_recorded_ext_base_consts, take_recorded_ext_base_consts, BabyBearChip, + RecordedExtBaseConst, BABY_BEAR_MODULUS_U64, + }, + stages::proof_shape::{log_heights_per_air_from_proof, trace_id_order_from_static_heights}, + RootF, StaticVerifierCircuit, +}; + +const END_TO_END_K: u32 = 22; +const END_TO_END_LOOKUP_BITS: usize = END_TO_END_K as usize - 1; +const END_TO_END_MIN_ROWS: usize = 32768; + +fn run_mock( + instance_columns: usize, + expect_satisfied: bool, + build: impl FnOnce(&mut Context, BabyBearExtChip), +) { + let mut builder = BaseCircuitBuilder::from_stage(CircuitBuilderStage::Mock) + .use_k(END_TO_END_K as usize) + .use_lookup_bits(END_TO_END_LOOKUP_BITS) + .use_instance_columns(instance_columns); + + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + if expect_satisfied { + build(ctx, ext_chip); + } else { + // Disable guarded debug assertions in BabyBearChip, and catch host-side + // panics (e.g. deterministic metadata shape checks) that fire before the + // MockProver can verify constraints. + let build_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + crate::utils::with_debug_asserts_disabled(|| build(ctx, ext_chip)); + })); + if build_result.is_err() { + return; + } + } + + let params = builder.calculate_params(Some(END_TO_END_MIN_ROWS)); + assert!( + params + .num_advice_per_phase + .first() + .copied() + .unwrap_or_default() + >= STATIC_VERIFIER_NUM_ADVICE_COLS + ); + assert!( + params + .num_lookup_advice_per_phase + .first() + .copied() + .unwrap_or_default() + >= STATIC_VERIFIER_LOOKUP_ADVICE_COLS + ); + + let pvs: Vec> = if instance_columns == 0 { + vec![] + } else { + builder + .assigned_instances + .iter() + .map(|vs| vs.iter().map(|w| *w.value()).collect_vec()) + .collect_vec() + }; + let prover = MockProver::run(END_TO_END_K, &builder, pvs) + .expect("mock prover should initialize for pipeline end-to-end circuit"); + if expect_satisfied { + prover.assert_satisfied(); + } else { + assert!( + prover.verify().is_err(), + "expected pipeline end-to-end constraints to fail", + ); + } +} + +fn test_engine() -> BabyBearBn254Poseidon2CpuEngine { + BabyBearBn254Poseidon2CpuEngine::new(test_system_params_small(2, 8, 3)) +} + +fn assert_fixture_constraints_only(engine: &BabyBearBn254Poseidon2CpuEngine, fixture: Fx) +where + Fx: TestFixture, +{ + let (vk, proof) = fixture.keygen_and_prove(engine); + let log_heights_per_air = log_heights_per_air_from_proof(&proof); + let dummy_onion_commit = Default::default(); + let circuit = StaticVerifierCircuit::try_new(vk, dummy_onion_commit, &log_heights_per_air) + .expect("static circuit params"); + + run_mock(0, true, |ctx, ext_chip| { + circuit.populate_verify_stark_constraints(ctx, &ext_chip, &proof); + }); +} + +fn prank_recorded_ext_constant( + ctx: &mut Context, + records: &[RecordedExtBaseConst], + family: &str, + constant: u64, +) { + let record = records + .iter() + .find(|record| record.constant == constant) + .unwrap_or_else(|| panic!("missing recorded ext-base constant for {family}={constant}")); + record + .cell + .debug_prank(ctx, Fr::from((constant + 1) % BABY_BEAR_MODULUS_U64)); +} + +#[test] +fn pipeline_constraints_fail_when_ext_constant_families_are_pranked() { + let engine = test_engine(); + let (vk, proof) = InteractionsFixture11.keygen_and_prove(&engine); + + let l_skip = vk.inner.params.l_skip; + let subgroup_root = RootF::two_adic_generator(l_skip).as_canonical_u64(); + let bus_constant = vk + .inner + .per_air + .iter() + .flat_map(|air| air.symbolic_constraints.interactions.iter()) + .map(|interaction| u64::from(interaction.bus_index) + 1) + .find(|&value| value > 1) + .unwrap_or(1); + let normalization_family_constants = (1..=31usize) + .map(|pow| { + (0..pow) + .fold(RootF::ONE, |acc, _| acc.halve()) + .as_canonical_u64() + }) + .collect::>(); + let base_families = [ + ("one", 1u64), + ("two", 2u64), + ("subgroup_root", subgroup_root), + ("bus_index_plus_one", bus_constant), + ]; + + let log_heights_per_air = log_heights_per_air_from_proof(&proof); + let trace_id_to_air_id = trace_id_order_from_static_heights(&vk.inner, &log_heights_per_air); + let stacked_layouts = build_stacked_layouts_for_static_vk(&vk.inner, &log_heights_per_air); + run_mock(1, false, move |ctx, ext_chip| { + let proof_wire = load_proof_wire(ctx, &ext_chip, &proof, &log_heights_per_air); + clear_recorded_ext_base_consts(); + constrained_verify( + ctx, + &ext_chip, + &vk, + &proof_wire, + &trace_id_to_air_id, + &log_heights_per_air, + &stacked_layouts, + ); + let records = take_recorded_ext_base_consts(); + for (family, constant) in base_families { + prank_recorded_ext_constant(ctx, &records, family, constant); + } + let normalization_constant = records + .iter() + .find(|record| normalization_family_constants.contains(&record.constant)) + .map(|record| record.constant) + .unwrap_or(1); + prank_recorded_ext_constant(ctx, &records, "normalization", normalization_constant); + }); +} + +#[test] +fn pipeline_constraints_only_matches_native_for_mixture_fixture() { + let engine = test_engine(); + assert_fixture_constraints_only( + &engine, + MixtureFixture::standard(5, engine.config().clone()), + ); +} + +#[test] +fn pipeline_constraints_only_matches_native_for_interactions_fixture() { + let engine = test_engine(); + assert_fixture_constraints_only(&engine, InteractionsFixture11); +} + +#[test] +fn pipeline_constraints_only_matches_native_for_cached_fixture() { + let engine = test_engine(); + assert_fixture_constraints_only(&engine, CachedFixture11::new(engine.config().clone())); +} + +#[cfg(feature = "cell-profiling")] +#[test] +fn pipeline_cell_count_profiling() { + use openvm_stark_backend::{SystemParams, WhirProximityStrategy}; + use openvm_stark_sdk::{ + config::{ + log_up_params::log_up_security_params_baby_bear_100_bits, + root_params_with_100_bits_security, + }, + openvm_stark_backend::test_utils::MixtureFixture, + }; + + let system_params = root_params_with_100_bits_security(); + let (vk, proof) = { + #[cfg(feature = "cuda")] + { + let engine = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine::new(system_params); + let fx = MixtureFixture::standard(5, engine.config().clone()); + fx.keygen_and_prove(&engine) + } + #[cfg(not(feature = "cuda"))] + { + let engine: BabyBearBn254Poseidon2CpuEngine = + BabyBearBn254Poseidon2CpuEngine::new(system_params); + let fx = MixtureFixture::standard(5, engine.config().clone()); + fx.keygen_and_prove(&engine) + } + }; + let log_heights_per_air = log_heights_per_air_from_proof(&proof); + let dummy_onion_commit = Default::default(); + let circuit = StaticVerifierCircuit::try_new(vk, dummy_onion_commit, &log_heights_per_air) + .expect("static circuit params"); + + let profile_dir = std::env::var("OPENVM_PROFILE_DIR").unwrap_or_else(|_| "profile".to_string()); + std::env::set_var("OPENVM_PROFILE_DIR", &profile_dir); + + let mut builder = BaseCircuitBuilder::from_stage(CircuitBuilderStage::Mock) + .use_k(END_TO_END_K as usize) + .use_lookup_bits(END_TO_END_LOOKUP_BITS) + .use_instance_columns(0); + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + + let initial_cells = ctx.advice.len(); + circuit.populate_verify_stark_constraints(ctx, &ext_chip, &proof); + let final_cells = ctx.advice.len(); + assert!( + final_cells > initial_cells, + "expected advice cells to increase during populate_verify_stark_constraints" + ); +} diff --git a/patches/openvm-static-verifier/src/stages/mod.rs b/patches/openvm-static-verifier/src/stages/mod.rs new file mode 100644 index 00000000..2877b654 --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/mod.rs @@ -0,0 +1,6 @@ +pub mod batch_constraints; +pub mod full_pipeline; +pub mod proof_shape; +pub(crate) mod shared_math; +pub mod stacked_reduction; +pub mod whir; diff --git a/patches/openvm-static-verifier/src/stages/proof_shape/mod.rs b/patches/openvm-static-verifier/src/stages/proof_shape/mod.rs new file mode 100644 index 00000000..865f8131 --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/proof_shape/mod.rs @@ -0,0 +1,40 @@ +use core::cmp::Reverse; + +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig, + openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey0, proof::Proof}, +}; + +/// Per-AIR log₂ trace heights from `proof.trace_vdata`, in AIR index order. +/// +/// Panics if any entry is [`None`]. The static verifier requires a trace for every AIR. +pub fn log_heights_per_air_from_proof(proof: &Proof) -> Vec { + proof + .trace_vdata + .iter() + .enumerate() + .map(|(air_id, tv)| { + tv.as_ref() + .unwrap_or_else(|| panic!("missing trace_vdata for air_id {air_id}")) + .log_height + }) + .collect() +} + +/// Permutation of AIR indices when every AIR has a trace, ordered by descending `log_height` +/// (tie-break: lower `air_id` first). For a proof with full `trace_vdata`, this matches that +/// proof's trace ordering. +pub(crate) fn trace_id_order_from_static_heights( + mvk0: &MultiStarkVerifyingKey0, + log_heights_per_air: &[usize], +) -> Vec { + let num_airs = mvk0.per_air.len(); + assert_eq!( + log_heights_per_air.len(), + num_airs, + "log_heights_per_air length must match VK per_air count" + ); + let mut trace_id_to_air_id: Vec = (0..num_airs).collect(); + trace_id_to_air_id.sort_by_key(|&air_id| (Reverse(log_heights_per_air[air_id]), air_id)); + trace_id_to_air_id +} diff --git a/patches/openvm-static-verifier/src/stages/shared_math.rs b/patches/openvm-static-verifier/src/stages/shared_math.rs new file mode 100644 index 00000000..64754450 --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/shared_math.rs @@ -0,0 +1,99 @@ +use halo2_base::Context; +use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeCharacteristicRing; + +use crate::{ + field::baby_bear::{BabyBearExtChip, BabyBearWire}, + Fr, RootF, +}; + +pub(crate) type BabyBearExtWire = crate::field::baby_bear::BabyBearExtWire; + +pub(crate) fn column_openings_by_rot_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + openings: &[BabyBearExtWire], + need_rot: bool, +) -> Vec<(BabyBearExtWire, BabyBearExtWire)> { + if need_rot { + assert!( + openings.len().is_multiple_of(2), + "rotated opening vector must be even", + ); + openings + .chunks_exact(2) + .map(|chunk| (chunk[0], chunk[1])) + .collect::>() + } else { + let zero = ext_chip.zero(ctx); + openings + .iter() + .map(|opening| (*opening, zero)) + .collect::>() + } +} + +pub(crate) fn horner_eval_ext_poly_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + coeffs: &[BabyBearExtWire], + x: &BabyBearExtWire, +) -> BabyBearExtWire { + if coeffs.is_empty() { + return ext_chip.zero(ctx); + } + // Pre-reduce x so that ext_mul doesn't redundantly reduce the same + // high-max_bits components on every Horner step. + let x_reduced = ext_chip.reduce_max_bits(ctx, *x); + let mut acc = *coeffs.last().unwrap(); + for coeff in coeffs.iter().rev().skip(1) { + acc = ext_chip.mul(ctx, acc, x_reduced); + acc = ext_chip.add(ctx, acc, *coeff); + } + acc +} + +pub(crate) fn horner_eval_ext_poly_f_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + coeffs: &[BabyBearExtWire], + x: &BabyBearWire, +) -> BabyBearExtWire { + if coeffs.is_empty() { + return ext_chip.zero(ctx); + } + // Pre-reduce x so that each mul_add step inside the loop doesn't redundantly + // reduce the same high-max_bits value on every iteration. + let x_reduced = ext_chip.base().reduce_max_bits(ctx, *x); + let mut acc = *coeffs.last().unwrap(); + for coeff in coeffs.iter().rev().skip(1) { + acc = ext_chip.scalar_mul_add(ctx, acc, x_reduced, *coeff); + } + acc +} + +pub(crate) fn interpolate_quadratic_at_012_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + evals: [&BabyBearExtWire; 3], + x: &BabyBearExtWire, +) -> BabyBearExtWire { + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let two = ext_chip.from_base_const(ctx, RootF::TWO); + let inv_two = RootF::ONE.halve(); + + let x_minus_one = ext_chip.sub(ctx, *x, one); + let x_minus_two = ext_chip.sub(ctx, *x, two); + let x_times_x_minus_one = ext_chip.mul(ctx, *x, x_minus_one); + let x_times_x_minus_two = ext_chip.mul(ctx, *x, x_minus_two); + let x_minus_one_times_x_minus_two = ext_chip.mul(ctx, x_minus_one, x_minus_two); + + let l0 = ext_chip.mul_base_const(ctx, x_minus_one_times_x_minus_two, inv_two); + let l1 = ext_chip.neg(ctx, x_times_x_minus_two); + let l2 = ext_chip.mul_base_const(ctx, x_times_x_minus_one, inv_two); + + let term0 = ext_chip.mul(ctx, *evals[0], l0); + let term1 = ext_chip.mul(ctx, *evals[1], l1); + let term2 = ext_chip.mul(ctx, *evals[2], l2); + let sum01 = ext_chip.add(ctx, term0, term1); + ext_chip.add(ctx, sum01, term2) +} diff --git a/patches/openvm-static-verifier/src/stages/stacked_reduction/mod.rs b/patches/openvm-static-verifier/src/stages/stacked_reduction/mod.rs new file mode 100644 index 00000000..99ea2f2a --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/stacked_reduction/mod.rs @@ -0,0 +1,318 @@ +use std::collections::HashMap; + +use halo2_base::Context; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig, + openvm_stark_backend::{p3_field::PrimeCharacteristicRing, prover::stacked_pcs::StackedLayout}, +}; + +use crate::{ + field::baby_bear::{BabyBearExtChip, BabyBearExtWire, ReducedBabyBearExtWire}, + profiling::CellProfiler, + stages::{ + batch_constraints::{ + eval_eq_mle_binary_assigned, eval_eq_prism_assigned, eval_eq_uni_at_one_assigned, + eval_rot_kernel_prism_assigned, + }, + shared_math::{ + column_openings_by_rot_assigned, horner_eval_ext_poly_assigned, + interpolate_quadratic_at_012_assigned, + }, + }, + transcript::TranscriptChip, + Fr, RootF, +}; + +#[derive(Clone, Debug)] +pub struct StackedReductionIntermediatesWire { + pub stacking_openings: Vec>, + pub u: Vec, +} + +#[derive(Clone, Debug)] +pub struct StackingProofWire { + pub univariate_round_coeffs: Vec, + pub sumcheck_round_polys: Vec>, + pub stacking_openings: Vec>, +} + +pub(crate) fn load_stacking_proof_wire( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + stacking_proof: &openvm_stark_sdk::openvm_stark_backend::proof::StackingProof, +) -> StackingProofWire { + let univariate_round_coeffs = stacking_proof + .univariate_round_coeffs + .iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>(); + let sumcheck_round_polys = stacking_proof + .sumcheck_round_polys + .iter() + .map(|poly| { + poly.iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>() + }) + .collect::>(); + let stacking_openings = stacking_proof + .stacking_openings + .iter() + .map(|row| { + row.iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>() + }) + .collect::>(); + StackingProofWire { + univariate_round_coeffs, + sumcheck_round_polys, + stacking_openings, + } +} + +fn eval_in_uni_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + l_skip: usize, + n: isize, + z: BabyBearExtWire, +) -> BabyBearExtWire { + debug_assert!(n >= -(l_skip as isize)); + if n.is_negative() { + let z_pow = ext_chip.pow_power_of_two(ctx, z, l_skip.wrapping_add_signed(n)); + eval_eq_uni_at_one_assigned(ctx, ext_chip, n.unsigned_abs(), &z_pow) + } else { + ext_chip.from_base_const(ctx, RootF::from_u64(1)) + } +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn constrain_stacked_reduction( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + transcript: &mut TranscriptChip, + stacking_wire: &StackingProofWire, + layouts: &[StackedLayout], + need_rot_per_commit: &[Vec], + l_skip: usize, + n_stack: usize, + batch_column_openings: &[Vec>], + r: &[BabyBearExtWire], + profiler: &mut CellProfiler, +) -> StackedReductionIntermediatesWire { + let omega_order = 1usize << l_skip; + let one = ext_chip.from_base_const(ctx, RootF::ONE); + + profiler.push("claim_batching", ctx.advice.len()); + + let mut lambda_idx = 0usize; + let lambda_indices_per_layout = layouts + .iter() + .enumerate() + .map(|(commit_idx, layout)| { + let need_rot_for_commit = &need_rot_per_commit[commit_idx]; + layout + .sorted_cols + .iter() + .map(|&(mat_idx, _col_idx, _slice)| { + lambda_idx += 1; + (lambda_idx - 1, need_rot_for_commit[mat_idx]) + }) + .collect::>() + }) + .collect::>(); + + let mut t_claims = Vec::with_capacity(lambda_idx); + for (trace_idx, parts) in batch_column_openings.iter().enumerate() { + let need_rot = need_rot_per_commit[0][trace_idx]; + let openings = parts[0] + .iter() + .map(|opening| opening.into()) + .collect::>(); + t_claims.extend(column_openings_by_rot_assigned( + ctx, ext_chip, &openings, need_rot, + )); + } + let mut commit_idx = 1usize; + for parts in batch_column_openings { + for cols in parts.iter().skip(1) { + let need_rot = need_rot_per_commit[commit_idx][0]; + let openings = cols + .iter() + .map(|opening| opening.into()) + .collect::>(); + t_claims.extend(column_openings_by_rot_assigned( + ctx, ext_chip, &openings, need_rot, + )); + commit_idx += 1; + } + } + + let lambda = transcript.sample_ext(ctx); + let lambda_sqr = ext_chip.mul(ctx, lambda, lambda); + let mut lambda_sqr_powers = Vec::with_capacity(t_claims.len()); + let mut cur_lambda_sqr = one; + for _ in 0..t_claims.len() { + lambda_sqr_powers.push(cur_lambda_sqr); + cur_lambda_sqr = ext_chip.mul(ctx, cur_lambda_sqr, lambda_sqr); + cur_lambda_sqr = ext_chip.reduce_max_bits(ctx, cur_lambda_sqr); + } + + let mut s_0 = ext_chip.zero(ctx); + for (i, ((claim, claim_rot), lambda_pow)) in + t_claims.iter().zip(lambda_sqr_powers.iter()).enumerate() + { + let claim_rot_lambda = ext_chip.mul(ctx, *claim_rot, lambda); + let batched_claim = ext_chip.add(ctx, *claim, claim_rot_lambda); + let term = if i == 0 { + batched_claim + } else { + ext_chip.mul(ctx, batched_claim, *lambda_pow) + }; + s_0 = ext_chip.add(ctx, s_0, term); + } + + profiler.pop(ctx.advice.len()); + profiler.push("univariate_sumcheck", ctx.advice.len()); + + let univariate_round_coeffs = &stacking_wire.univariate_round_coeffs; + let univariate_round_coeffs_raw = univariate_round_coeffs + .iter() + .map(|coeff| coeff.into()) + .collect::>(); + let mut s_0_sum_eval = ext_chip.zero(ctx); + for coeff in univariate_round_coeffs_raw.iter().step_by(omega_order) { + s_0_sum_eval = ext_chip.add(ctx, s_0_sum_eval, *coeff); + } + let s_0_sum_eval = + ext_chip.mul_base_const(ctx, s_0_sum_eval, RootF::from_u64(omega_order as u64)); + ext_chip.assert_equal(ctx, s_0, s_0_sum_eval); + + for coeff in univariate_round_coeffs { + transcript.observe_ext(ctx, coeff); + } + + let mut u = Vec::with_capacity(n_stack + 1); + u.push(transcript.sample_ext(ctx)); + + let sumcheck_round_polys = &stacking_wire.sumcheck_round_polys; + + let mut final_claim = + horner_eval_ext_poly_assigned(ctx, ext_chip, &univariate_round_coeffs_raw, &u[0]); + for round_poly in sumcheck_round_polys { + let s_j_1 = round_poly[0]; + let s_j_2 = round_poly[1]; + transcript.observe_ext(ctx, &s_j_1); + transcript.observe_ext(ctx, &s_j_2); + let u_j = transcript.sample_ext(ctx); + let s_j_1 = s_j_1.into(); + let s_j_2 = s_j_2.into(); + let s_j_0 = ext_chip.sub(ctx, final_claim, s_j_1); + final_claim = + interpolate_quadratic_at_012_assigned(ctx, ext_chip, [&s_j_0, &s_j_1, &s_j_2], &u_j); + u.push(u_j); + } + + profiler.pop(ctx.advice.len()); + profiler.push("derived_q_coeffs", ctx.advice.len()); + + let stacking_matrix_expected_widths = layouts + .iter() + .map(|layout| { + layout + .sorted_cols + .last() + .map(|(_, _, slice)| slice.col_idx + 1) + .expect("stacked layout must contain at least one column") + }) + .collect::>(); + let mut derived_q_coeffs = stacking_matrix_expected_widths + .iter() + .map(|&width| { + core::iter::repeat_with(|| ext_chip.zero(ctx)) + .take(width) + .collect::>() + }) + .collect::>(); + + // Determine whether any column needs rotation (to decide if rot_kernel is needed). + let any_need_rot = lambda_indices_per_layout + .iter() + .any(|indices| indices.iter().any(|&(_, rot)| rot)); + + // Cache per-n computations: (ind, eq_prism, rot_kernel). + let mut n_cache: HashMap = + HashMap::new(); + // Cache eq_mle results by (n, b_bits encoded as usize). + let mut eq_mle_cache: HashMap<(isize, usize), BabyBearExtWire> = HashMap::new(); + + for (commit_idx, layout) in layouts.iter().enumerate() { + let lambda_indices = &lambda_indices_per_layout[commit_idx]; + for (col_idx, &(_, _, s)) in layout.sorted_cols.iter().enumerate() { + let (lambda_idx, need_rot) = lambda_indices[col_idx]; + let n = s.log_height() as isize - l_skip as isize; + let n_lift = n.max(0) as usize; + let b_key = s.row_idx >> (l_skip + n_lift); + + let eq_mle = *eq_mle_cache.entry((n, b_key)).or_insert_with(|| { + let b_bits = (l_skip + n_lift..l_skip + n_stack) + .map(|j| ((s.row_idx >> j) & 1) == 1) + .collect::>(); + eval_eq_mle_binary_assigned(ctx, ext_chip, &u[n_lift + 1..], &b_bits) + }); + + let &mut (ind, eq_prism, rot_kernel) = n_cache.entry(n).or_insert_with(|| { + let ind = eval_in_uni_assigned(ctx, ext_chip, l_skip, n, u[0]); + let (l, rs_n) = if n.is_negative() { + ( + l_skip.wrapping_add_signed(n), + vec![ext_chip.pow_power_of_two(ctx, r[0], n.unsigned_abs())], + ) + } else { + (l_skip, r[..=n_lift].to_vec()) + }; + let eq_prism = eval_eq_prism_assigned(ctx, ext_chip, l, &u[..=n_lift], &rs_n); + let rot_kernel = if any_need_rot { + eval_rot_kernel_prism_assigned(ctx, ext_chip, l, &u[..=n_lift], &rs_n) + } else { + ext_chip.zero(ctx) + }; + (ind, eq_prism, rot_kernel) + }); + + let mut batched = ext_chip.mul(ctx, lambda_sqr_powers[lambda_idx], eq_prism); + if need_rot { + let lambda_rot = ext_chip.mul(ctx, lambda, rot_kernel); + let rot_term = ext_chip.mul(ctx, lambda_sqr_powers[lambda_idx], lambda_rot); + batched = ext_chip.add(ctx, batched, rot_term); + } + let batched_ind = ext_chip.mul(ctx, batched, ind); + let coeff = ext_chip.mul(ctx, eq_mle, batched_ind); + let updated = ext_chip.add(ctx, derived_q_coeffs[commit_idx][s.col_idx], coeff); + derived_q_coeffs[commit_idx][s.col_idx] = updated; + } + } + + profiler.pop(ctx.advice.len()); + profiler.push("final_verification", ctx.advice.len()); + + let stacking_openings = &stacking_wire.stacking_openings; + let mut final_sum = ext_chip.zero(ctx); + for (coeff_row, opening_row) in derived_q_coeffs.iter().zip(stacking_openings.iter()) { + for (coeff, opening) in coeff_row.iter().zip(opening_row.iter()) { + transcript.observe_ext(ctx, opening); + let term = ext_chip.mul(ctx, *coeff, opening.into()); + final_sum = ext_chip.add(ctx, final_sum, term); + } + } + + ext_chip.assert_equal(ctx, final_claim, final_sum); + + profiler.pop(ctx.advice.len()); + + StackedReductionIntermediatesWire { + stacking_openings: stacking_openings.clone(), + u, + } +} diff --git a/patches/openvm-static-verifier/src/stages/whir/mod.rs b/patches/openvm-static-verifier/src/stages/whir/mod.rs new file mode 100644 index 00000000..10e58024 --- /dev/null +++ b/patches/openvm-static-verifier/src/stages/whir/mod.rs @@ -0,0 +1,735 @@ +use halo2_base::{ + gates::{GateInstructions, RangeInstructions}, + utils::biguint_to_fe, + AssignedValue, Context, QuantumCell, +}; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::{ + BabyBearBn254Poseidon2Config as RootConfig, Digest as RootDigest, + }, + openvm_stark_backend::{ + keygen::types::MultiStarkVerifyingKey0, + p3_field::{ + BasedVectorSpace, Field, PrimeCharacteristicRing, PrimeField, PrimeField64, + TwoAdicField, + }, + proof::WhirProof, + }, +}; + +use crate::{ + field::baby_bear::{ + BabyBearChip, BabyBearExt4Wire, BabyBearExtChip, BabyBearExtWire, BabyBearWire, + ReducedBabyBearExtWire, ReducedBabyBearWire, BABY_BEAR_EXT_DEGREE, + }, + hash::poseidon2::{compress_bn254_digests, hash_babybear_slice_to_digest}, + profiling::CellProfiler, + stages::{ + batch_constraints::{eval_eq_mle_assigned, eval_eq_mle_ef_f_assigned}, + shared_math::{ + horner_eval_ext_poly_assigned, horner_eval_ext_poly_f_assigned, + interpolate_quadratic_at_012_assigned, + }, + }, + transcript::{digest_wire_from_root, TranscriptChip}, + Fr, RootEF, RootF, +}; + +#[derive(Clone, Debug)] +pub struct MerklePathWire { + pub leaf_values: Vec>, + pub siblings: Vec>, +} + +#[derive(Clone, Debug)] +pub struct WhirProofWire { + pub mu_pow_witness: ReducedBabyBearWire, + pub folding_pow_witnesses: Vec, + pub query_phase_pow_witnesses: Vec, + pub whir_sumcheck_polys: Vec<[ReducedBabyBearExtWire; 2]>, + pub ood_values: Vec, + pub final_poly: Vec, + pub codeword_commitment_roots: Vec>, + pub initial_round_merkle_paths: Vec>, + pub codeword_merkle_paths: Vec>, +} + +pub(crate) fn load_whir_proof_wire( + ctx: &mut Context, + base_chip: &crate::field::baby_bear::BabyBearChip, + ext_chip: &BabyBearExtChip, + whir_proof: &WhirProof, +) -> WhirProofWire { + let mu_pow_witness = base_chip.load_reduced_witness(ctx, whir_proof.mu_pow_witness); + let folding_pow_witnesses = whir_proof + .folding_pow_witnesses + .iter() + .map(|&witness| { + base_chip.load_reduced_witness(ctx, RootF::from_u64(witness.as_canonical_u64())) + }) + .collect::>(); + let query_phase_pow_witnesses = whir_proof + .query_phase_pow_witnesses + .iter() + .map(|&witness| { + base_chip.load_reduced_witness(ctx, RootF::from_u64(witness.as_canonical_u64())) + }) + .collect::>(); + let whir_sumcheck_polys = whir_proof + .whir_sumcheck_polys + .iter() + .map(|poly| { + poly.iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>() + .try_into() + .expect("WHIR sumcheck polynomial must have two evaluations") + }) + .collect::>(); + let ood_values = whir_proof + .ood_values + .iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>(); + let final_poly = whir_proof + .final_poly + .iter() + .map(|&value| ext_chip.load_reduced_witness(ctx, value)) + .collect::>(); + let codeword_commitment_roots = whir_proof + .codeword_commits + .iter() + .map(|&digest| ctx.load_witness(digest_to_fr(digest))) + .collect::>(); + + let initial_round_merkle_paths = whir_proof + .initial_round_opened_rows + .iter() + .zip(whir_proof.initial_round_merkle_proofs.iter()) + .map(|(rows_per_query, proofs_per_query)| { + rows_per_query + .iter() + .zip(proofs_per_query.iter()) + .map(|(opened_rows, merkle_proof)| { + let leaf_values = opened_rows + .iter() + .map(|row| { + row.iter() + .map(|&value| base_chip.load_reduced_witness(ctx, value)) + .collect::>() + }) + .collect::>(); + let siblings = merkle_proof + .iter() + .map(|&digest| ctx.load_witness(digest_to_fr(digest))) + .collect::>(); + MerklePathWire { + leaf_values, + siblings, + } + }) + .collect::>() + }) + .collect::>(); + + let codeword_merkle_paths = whir_proof + .codeword_opened_values + .iter() + .zip(whir_proof.codeword_merkle_proofs.iter()) + .map(|(values_per_query, proofs_per_query)| { + values_per_query + .iter() + .zip(proofs_per_query.iter()) + .map(|(opened_values, merkle_proof)| { + let leaf_values = opened_values + .iter() + .map(|value| { + ext_to_coeffs(*value) + .iter() + .map(|&coeff| { + base_chip.load_reduced_witness(ctx, RootF::from_u64(coeff)) + }) + .collect::>() + }) + .collect::>(); + let siblings = merkle_proof + .iter() + .map(|&digest| ctx.load_witness(digest_to_fr(digest))) + .collect::>(); + MerklePathWire { + leaf_values, + siblings, + } + }) + .collect::>() + }) + .collect::>(); + + WhirProofWire { + mu_pow_witness, + folding_pow_witnesses, + query_phase_pow_witnesses, + whir_sumcheck_polys, + ood_values, + final_poly, + codeword_commitment_roots, + initial_round_merkle_paths, + codeword_merkle_paths, + } +} + +pub(crate) fn ext_to_coeffs(value: RootEF) -> [u64; BABY_BEAR_EXT_DEGREE] { + core::array::from_fn(|i| { + >::as_basis_coefficients_slice(&value)[i] + .as_canonical_u64() + }) +} + +fn digest_to_fr(digest: RootDigest) -> Fr { + biguint_to_fe(&digest[0].as_canonical_biguint()) +} + +fn eval_mobius_eq_mle_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + u: &[BabyBearExtWire], + x: &[BabyBearExtWire], +) -> BabyBearExtWire { + assert_eq!(u.len(), x.len(), "mobius-eq arity mismatch"); + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let two = ext_chip.from_base_const(ctx, RootF::TWO); + let three = RootF::from_u64(3); + let mut acc = one; + // (1-2u)(1-x) + ux = (1-x) + u(3x-2) + for (u_i, x_i) in u.iter().zip(x.iter()) { + let one_minus_x = ext_chip.sub(ctx, one, *x_i); + let three_x_minus_two = ext_chip.mul_base_const(ctx, *x_i, three); + let three_x_minus_two = ext_chip.sub(ctx, three_x_minus_two, two); + let u_term = ext_chip.mul(ctx, *u_i, three_x_minus_two); + let factor = ext_chip.add(ctx, one_minus_x, u_term); + acc = ext_chip.mul(ctx, acc, factor); + } + acc +} + +fn eval_mle_evals_at_point_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + evals: &[BabyBearExtWire], + x: &[BabyBearExtWire], +) -> BabyBearExtWire { + assert_eq!( + evals.len(), + 1usize << x.len(), + "MLE table length must be 2^arity", + ); + let mut values = evals.to_vec(); + let mut len = values.len(); + for xj in x.iter().rev() { + len >>= 1; + for i in 0..len { + let lo = values[i]; + let hi = values[i + len]; + let diff = ext_chip.sub(ctx, hi, lo); + let weighted = ext_chip.mul(ctx, diff, *xj); + values[i] = ext_chip.add(ctx, lo, weighted); + } + } + values + .first() + .copied() + .expect("MLE reduction must produce one value") +} + +fn invert_base_assigned( + ctx: &mut Context, + base_chip: &BabyBearChip, + value: BabyBearWire, +) -> BabyBearWire { + let one = base_chip.one(ctx); + base_chip.div(ctx, one, value) +} + +fn query_root_from_bits_assigned( + ctx: &mut Context, + base_chip: &BabyBearChip, + query_bits: &[AssignedValue], + log_rs_domain_size: usize, +) -> BabyBearWire { + let gate = base_chip.range().gate(); + let omega = RootF::two_adic_generator(log_rs_domain_size); + let mut root = None; + for (bit_idx, &bit) in query_bits.iter().enumerate() { + let omega_pow = omega.exp_u64(1u64 << bit_idx).as_canonical_u64(); + let value = gate.select( + ctx, + QuantumCell::Constant(Fr::from(omega_pow)), + QuantumCell::Constant(Fr::one()), + bit, + ); + let selected = BabyBearWire { + value, + max_bits: crate::field::baby_bear::BABYBEAR_MAX_BITS, + }; + if let Some(prev) = &mut root { + *prev = base_chip.mul(ctx, *prev, selected); + } else { + root = Some(selected); + } + } + root.unwrap() +} + +fn binary_k_fold_assigned( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + mut values: Vec, + alphas: &[BabyBearExtWire], + x: BabyBearWire, +) -> BabyBearExtWire { + let base_chip = ext_chip.base(); + + let n = values.len(); + assert_eq!( + n, + 1usize << alphas.len(), + "binary-k fold value count must match 2^k", + ); + if alphas.is_empty() { + return values[0]; + } + + let k = alphas.len(); + let omega_k = RootF::two_adic_generator(k); + let omega_k_inv = omega_k.inverse(); + let tw: Vec = omega_k.powers().take(1usize << (k - 1)).collect(); + let half = RootF::ONE.halve(); + let inv_tw_half: Vec = omega_k_inv + .powers() + .take(1usize << (k - 1)) + .map(|p| p * half) + .collect(); + + let mut x_pow = base_chip.reduce_max_bits(ctx, x); + let x_inv = invert_base_assigned(ctx, base_chip, x); + let mut x_inv_pow = base_chip.reduce_max_bits(ctx, x_inv); + + for (j, alpha) in alphas.iter().enumerate() { + let m = n >> (j + 1); + for i in 0..m { + let t = base_chip.mul_const(ctx, x_pow, tw[i << j]); + let t_inv_half = base_chip.mul_const(ctx, x_inv_pow, inv_tw_half[i << j]); + + let lo = values[i]; + let hi = values[i + m]; + let lo_minus_hi = ext_chip.sub(ctx, lo, hi); + let mut alpha_minus_t = *alpha; + alpha_minus_t.0[0] = base_chip.sub(ctx, alpha_minus_t.0[0], t); + let fold = ext_chip.mul(ctx, alpha_minus_t, lo_minus_hi); + values[i] = ext_chip.scalar_mul_add(ctx, fold, t_inv_half, lo); + } + x_pow = base_chip.square(ctx, x_pow); + x_pow = base_chip.reduce_max_bits(ctx, x_pow); + x_inv_pow = base_chip.square(ctx, x_inv_pow); + x_inv_pow = base_chip.reduce_max_bits(ctx, x_inv_pow); + } + values[0] +} + +fn tree_compress_assigned_digests( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + digests: Vec>, +) -> AssignedValue { + assert!( + digests.len().is_power_of_two(), + "tree_compress inputs must be power-of-two length" + ); + let mut level = digests; + while level.len() > 1 { + let mut next = Vec::with_capacity(level.len() / 2); + for pair in level.chunks_exact(2) { + next.push(compress_bn254_digests( + ctx, + ext_chip.range(), + pair[0], + pair[1], + )); + } + level = next; + } + level + .pop() + .expect("tree_compress must output one digest for non-empty inputs") +} + +fn constrain_merkle_path( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + query_bits: &[AssignedValue], + merkle_path: &MerklePathWire, + root_digest: AssignedValue, +) { + assert!( + merkle_path.leaf_values.len().is_power_of_two(), + "leaf input count must be power of two" + ); + + let gate = ext_chip.range().gate(); + + assert_eq!( + merkle_path.siblings.len(), + query_bits.len(), + "merkle path depth must match query bits", + ); + + let leaf_hashes = merkle_path + .leaf_values + .iter() + .map(|leaf| hash_babybear_slice_to_digest(ctx, ext_chip.range(), leaf)) + .collect::>(); + + let mut cur = tree_compress_assigned_digests(ctx, ext_chip, leaf_hashes); + let query_bits = query_bits.to_vec(); + + for (bit, &sibling) in query_bits.iter().zip(merkle_path.siblings.iter()) { + // Select input order first, then compress once (instead of compressing + // both orderings and selecting after). Halves Poseidon2 calls per level. + let left = gate.select(ctx, sibling, cur, *bit); + let right = gate.select(ctx, cur, sibling, *bit); + cur = compress_bn254_digests(ctx, ext_chip.range(), left, right); + } + + ctx.constrain_equal(&cur, &root_digest); +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn constrain_whir_verification( + ctx: &mut Context, + ext_chip: &BabyBearExtChip, + transcript: &mut TranscriptChip, + mvk0: &MultiStarkVerifyingKey0, + whir_wire: &WhirProofWire, + stacking_openings: &[Vec], + initial_commitment_roots: &[AssignedValue], + u_cube: &[BabyBearExtWire], + profiler: &mut CellProfiler, +) { + let gate = ext_chip.range().gate(); + let params = &mvk0.params; + let k_whir = params.k_whir(); + let num_whir_rounds = params.num_whir_rounds(); + + profiler.push("mu_pows_and_claim", ctx.advice.len()); + + let mu_pow_witness = whir_wire.mu_pow_witness; + transcript.check_witness(ctx, params.whir.mu_pow_bits, &mu_pow_witness); + let mu_challenge = transcript.sample_ext(ctx); + + let folding_pow_witnesses = &whir_wire.folding_pow_witnesses; + let query_phase_pow_witnesses = &whir_wire.query_phase_pow_witnesses; + let whir_sumcheck_polys = &whir_wire.whir_sumcheck_polys; + let ood_values = &whir_wire.ood_values; + let final_poly_reduced = &whir_wire.final_poly; + let final_poly = final_poly_reduced + .iter() + .map(|coeff| coeff.into()) + .collect::>(); + let codeword_commitment_roots = &whir_wire.codeword_commitment_roots; + let codeword_commitment_digests = codeword_commitment_roots + .iter() + .copied() + .map(digest_wire_from_root) + .collect::>(); + + let total_width = stacking_openings.iter().map(Vec::len).sum::(); + let one = ext_chip.from_base_const(ctx, RootF::ONE); + let mut mu_pows = Vec::with_capacity(total_width); + let mut mu_pow = one; + for _ in 0..total_width { + mu_pows.push(mu_pow); + mu_pow = ext_chip.mul(ctx, mu_pow, mu_challenge); + mu_pow = ext_chip.reduce_max_bits(ctx, mu_pow); + } + + let mut final_claim = ext_chip.zero(ctx); + let mut mu_idx = 0usize; + for commit_openings in stacking_openings { + for opening in commit_openings { + let weighted = if mu_idx == 0 { + (*opening).into() + } else { + ext_chip.mul(ctx, opening.into(), mu_pows[mu_idx]) + }; + final_claim = ext_chip.add(ctx, final_claim, weighted); + mu_idx += 1; + } + } + + profiler.pop(ctx.advice.len()); + + let mut folding_alphas = Vec::new(); + let mut z0_challenges = Vec::new(); + let mut gammas = Vec::with_capacity(num_whir_rounds); + let mut query_indices = Vec::new(); + let mut folding_counts_per_round = Vec::with_capacity(num_whir_rounds); + let mut query_counts_per_round = Vec::with_capacity(num_whir_rounds); + let mut query_index_bits = Vec::new(); + let mut zs_per_round = Vec::with_capacity(num_whir_rounds); + + let mut sumcheck_cursor = 0usize; + let mut folding_pow_cursor = 0usize; + let mut log_rs_domain_size = params.l_skip + params.n_stack + params.log_blowup; + + for (round_idx, round_params) in params.whir.rounds.iter().enumerate() { + let round_label = format!("round_{round_idx}"); + profiler.push(&round_label, ctx.advice.len()); + + let is_initial_round = round_idx == 0; + let is_final_round = round_idx + 1 == num_whir_rounds; + let mut alphas_round = Vec::new(); + + profiler.push("sumcheck", ctx.advice.len()); + for _ in 0..k_whir { + if let Some(evals) = whir_sumcheck_polys.get(sumcheck_cursor) { + let ev1 = evals[0]; + let ev2 = evals[1]; + transcript.observe_ext(ctx, &ev1); + transcript.observe_ext(ctx, &ev2); + + let pow_witness = folding_pow_witnesses[folding_pow_cursor]; + folding_pow_cursor += 1; + transcript.check_witness(ctx, params.whir.folding_pow_bits, &pow_witness); + + let alpha = transcript.sample_ext(ctx); + alphas_round.push(alpha); + folding_alphas.push(alpha); + + let ev1 = ev1.into(); + let ev2 = ev2.into(); + let ev0 = ext_chip.sub(ctx, final_claim, ev1); + final_claim = interpolate_quadratic_at_012_assigned( + ctx, + ext_chip, + [&ev0, &ev1, &ev2], + &alpha, + ); + sumcheck_cursor += 1; + } + } + folding_counts_per_round.push(alphas_round.len()); + profiler.pop(ctx.advice.len()); + + let y0 = if is_final_round { + for coeff in final_poly_reduced { + transcript.observe_ext(ctx, coeff); + } + None + } else { + transcript.observe_commit(ctx, &codeword_commitment_digests[round_idx]); + let z0 = transcript.sample_ext(ctx); + z0_challenges.push(z0); + + let y0 = ood_values[round_idx]; + transcript.observe_ext(ctx, &y0); + Some(y0) + }; + + transcript.check_witness( + ctx, + params.whir.query_phase_pow_bits, + &query_phase_pow_witnesses[round_idx], + ); + + let query_bits = log_rs_domain_size - k_whir; + let num_queries = round_params.num_queries; + query_counts_per_round.push(num_queries); + + let mut ys_round = Vec::with_capacity(num_queries); + let mut zs_round = Vec::with_capacity(num_queries); + + profiler.push("queries", ctx.advice.len()); + for query_idx in 0..num_queries { + let query_index = transcript.sample_bits(ctx, query_bits); + query_index_bits.push(query_bits); + query_indices.push(query_index); + let query_bits_vec = if query_bits == 0 { + Vec::new() + } else { + gate.num_to_bits(ctx, query_index, query_bits) + }; + let zi_root = query_root_from_bits_assigned( + ctx, + ext_chip.base(), + &query_bits_vec, + log_rs_domain_size, + ); + let zi = ext_chip.base().pow_power_of_two(ctx, zi_root, k_whir); + + let yi = if is_initial_round { + let mut codeword_vals = vec![None; 1usize << k_whir]; + let mut mu_power_idx = 0usize; + for (commit_idx, commit_openings) in stacking_openings.iter().enumerate() { + let merkle_path = &whir_wire.initial_round_merkle_paths[commit_idx][query_idx]; + constrain_merkle_path( + ctx, + ext_chip, + &query_bits_vec, + merkle_path, + initial_commitment_roots[commit_idx], + ); + for col_idx in 0..commit_openings.len() { + let mu_pow = mu_pows[mu_power_idx]; + let is_first_mu = mu_power_idx == 0; + for (row_idx, row) in merkle_path.leaf_values.iter().enumerate() { + let opened_base = row[col_idx].into(); + codeword_vals[row_idx] = if let Some(prev) = codeword_vals[row_idx] { + Some(ext_chip.scalar_mul_add(ctx, mu_pow, opened_base, prev)) + } else if is_first_mu { + Some(ext_chip.from_base_var(ctx, opened_base)) + } else { + Some(ext_chip.scalar_mul(ctx, mu_pow, opened_base)) + }; + } + mu_power_idx += 1; + } + } + + let codeword_vals = codeword_vals.into_iter().flatten().collect::>(); + binary_k_fold_assigned(ctx, ext_chip, codeword_vals, &alphas_round, zi_root) + } else { + let merkle_path = &whir_wire.codeword_merkle_paths[round_idx - 1][query_idx]; + constrain_merkle_path( + ctx, + ext_chip, + &query_bits_vec, + merkle_path, + codeword_commitment_roots[round_idx - 1], + ); + + let opened_values = merkle_path + .leaf_values + .iter() + .map(|row| BabyBearExt4Wire(core::array::from_fn(|idx| row[idx].into()))) + .collect::>(); + binary_k_fold_assigned(ctx, ext_chip, opened_values, &alphas_round, zi_root) + }; + + zs_round.push(zi); + ys_round.push(yi); + } + profiler.pop(ctx.advice.len()); + + profiler.push("gamma_accumulation", ctx.advice.len()); + let gamma = transcript.sample_ext(ctx); + if let Some(y0) = y0 { + let y0_term = ext_chip.mul(ctx, y0.into(), gamma); + final_claim = ext_chip.add(ctx, final_claim, y0_term); + } + let mut gamma_pow = ext_chip.mul(ctx, gamma, gamma); + for yi in &ys_round { + let term = ext_chip.mul(ctx, *yi, gamma_pow); + final_claim = ext_chip.add(ctx, final_claim, term); + gamma_pow = ext_chip.mul(ctx, gamma_pow, gamma); + } + + gammas.push(gamma); + profiler.pop(ctx.advice.len()); + + zs_per_round.push(zs_round); + log_rs_domain_size = log_rs_domain_size.saturating_sub(1); + profiler.pop(ctx.advice.len()); + } + + profiler.push("final_verification", ctx.advice.len()); + let rounds = query_counts_per_round.len(); + let t = k_whir * rounds; + + profiler.push("eq_mle_prefix_suffix", ctx.advice.len()); + let prefix = eval_mobius_eq_mle_assigned(ctx, ext_chip, &u_cube[..t], &folding_alphas[..t]); + let suffix = eval_mle_evals_at_point_assigned(ctx, ext_chip, &final_poly, &u_cube[t..]); + let mut final_acc = ext_chip.mul(ctx, prefix, suffix); + profiler.pop(ctx.advice.len()); + + let mut alpha_offset = k_whir; + for round_idx in 0..rounds { + let final_round_label = format!("final_round_{round_idx}"); + profiler.push(&final_round_label, ctx.advice.len()); + + let gamma = &gammas[round_idx]; + let alpha_slc = &folding_alphas[alpha_offset..t]; + let slc_len = (t - alpha_offset) + 1; + + if round_idx + 1 != rounds { + profiler.push("z0_ood_eval", ctx.advice.len()); + let z0 = &z0_challenges[round_idx]; + let mut z0_pows = Vec::with_capacity(slc_len); + z0_pows.push(*z0); + for _ in 1..slc_len { + let prev = z0_pows.last().unwrap(); + let next = ext_chip.square(ctx, *prev); + z0_pows.push(next); + } + let z0_max = *z0_pows.last().unwrap(); + // Pre-reduce z0_pows so eq_mle doesn't redundantly reduce them. + let z0_pows_reduced: Vec<_> = z0_pows + .iter() + .map(|p| ext_chip.reduce_max_bits(ctx, *p)) + .collect(); + let eq = eval_eq_mle_assigned( + ctx, + ext_chip, + alpha_slc, + &z0_pows_reduced[..z0_pows_reduced.len().saturating_sub(1)], + ); + let poly_eval = horner_eval_ext_poly_assigned(ctx, ext_chip, &final_poly, &z0_max); + let term = ext_chip.mul(ctx, *gamma, eq); + let term = ext_chip.mul(ctx, term, poly_eval); + final_acc = ext_chip.add(ctx, final_acc, term); + profiler.pop(ctx.advice.len()); + } + + profiler.push("query_point_evals", ctx.advice.len()); + let mut gamma_pow = ext_chip.mul(ctx, *gamma, *gamma); + for zi in zs_per_round[round_idx].iter() { + let mut zi_pows = Vec::with_capacity(slc_len); + zi_pows.push(*zi); + for _ in 1..slc_len { + let prev = zi_pows.last().unwrap(); + let next = ext_chip.base().square(ctx, *prev); + zi_pows.push(next); + } + // Pre-reduce zi_pows so eq_mle and poly eval don't redundantly reduce. + let zi_pows_reduced: Vec<_> = zi_pows + .iter() + .map(|p| ext_chip.base().reduce_max_bits(ctx, *p)) + .collect(); + + let eq = eval_eq_mle_ef_f_assigned( + ctx, + ext_chip, + alpha_slc, + &zi_pows_reduced[..zi_pows_reduced.len().saturating_sub(1)], + ); + + let poly_eval = horner_eval_ext_poly_f_assigned( + ctx, + ext_chip, + &final_poly, + zi_pows_reduced.last().unwrap(), + ); + + let term = ext_chip.mul(ctx, gamma_pow, eq); + let term = ext_chip.mul(ctx, term, poly_eval); + final_acc = ext_chip.add(ctx, final_acc, term); + gamma_pow = ext_chip.mul(ctx, gamma_pow, *gamma); + } + profiler.pop(ctx.advice.len()); + + profiler.pop(ctx.advice.len()); + alpha_offset += k_whir; + } + + ext_chip.assert_equal(ctx, final_acc, final_claim); + profiler.pop(ctx.advice.len()); +} diff --git a/patches/openvm-static-verifier/src/transcript/mod.rs b/patches/openvm-static-verifier/src/transcript/mod.rs new file mode 100644 index 00000000..8aa6de44 --- /dev/null +++ b/patches/openvm-static-verifier/src/transcript/mod.rs @@ -0,0 +1,377 @@ +use core::{array, iter}; +use std::sync::OnceLock; + +use halo2_base::{ + gates::{GateInstructions, RangeInstructions}, + halo2_proofs::arithmetic::Field, + utils::{biguint_to_fe, fe_to_biguint}, + AssignedValue, Context, QuantumCell, +}; +use num_bigint::BigUint; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::{Bn254Scalar, Digest as RootDigest}, + openvm_stark_backend::p3_field::{Field as P3Field, PrimeField}, +}; + +use crate::{ + field::baby_bear::{ + BabyBearChip, BabyBearExt4Wire, BabyBearExtWire, BabyBearWire, ReducedBabyBearExtWire, + ReducedBabyBearWire, BABY_BEAR_BITS, BABY_BEAR_MODULUS_U64, + }, + hash::{ + poseidon2::{pack_base_2_31_cells, Poseidon2State, DIGEST_WIDTH, POSEIDON2_RATE}, + POSEIDON2_PARAMS, POSEIDON2_WIDTH, + }, + Fr, +}; + +/// Number of BabyBear values bit-packed into one BN254 word (base-2^31). +/// = floor(254 / 31) = 8 +const NUM_OBS_PER_WORD: usize = 8; + +/// Number of BabyBear samples extracted from one BN254 word (base-BabyBear decomposition). +/// Must match `compute_num_samples_per_elem` in `MultiFieldTranscript`. +const NUM_SAMPLES_PER_WORD: usize = 5; + +/// Precomputed bounds for the base-BabyBear hint decomposition. +/// +/// Below `k = NUM_SAMPLES_PER_WORD`. +struct BaseBabyBearDecompBounds { + /// floor((q-1) / p^k) as a field element, for the boundary equality check. + top_quotient_max_fe: Fr, + /// floor((q-1) / p^k) + 1, for the range check. + top_quotient_max_plus_one: BigUint, + /// One more than the maximum lower part when top quotient is at its max. + lower_max_plus_one: BigUint, + /// p^k as a BigUint. + pow_k: BigUint, +} + +fn base_baby_bear_decomp_bounds() -> &'static BaseBabyBearDecompBounds { + static BOUNDS: OnceLock = OnceLock::new(); + BOUNDS.get_or_init(|| { + let p = BigUint::from(BABY_BEAR_MODULUS_U64); + let one = BigUint::from(1u64); + let modulus = ::order(); + let modulus_minus_one = &modulus - &one; + let pow_k = p.pow(NUM_SAMPLES_PER_WORD as u32); + let q_k_max = &modulus_minus_one / &pow_k; + let lower_max = modulus_minus_one - &q_k_max * &pow_k; + BaseBabyBearDecompBounds { + top_quotient_max_fe: biguint_to_fe(&q_k_max), + top_quotient_max_plus_one: &q_k_max + &one, + lower_max_plus_one: lower_max + one, + pow_k, + } + }) +} + +/// Decompose a BN254 field element into base-BabyBear digits using the +/// witness-and-verify (hint) approach. +/// +/// This helper only computes the decomposition off-circuit and loads the resulting +/// raw digit cells plus top quotient as witnesses. Constraints must be enforced +/// separately before the digits are wrapped as `BabyBearWire`s. +fn load_base_baby_bear_decomposition_witness( + ctx: &mut Context, + packed: AssignedValue, +) -> ([AssignedValue; NUM_SAMPLES_PER_WORD], AssignedValue) { + let p = BigUint::from(BABY_BEAR_MODULUS_U64); + + // Witness: compute digits and top quotient out-of-circuit. + let mut value = fe_to_biguint(packed.value()); + let digit_witnesses_big: [BigUint; NUM_SAMPLES_PER_WORD] = array::from_fn(|_| { + let digit = &value % &p; + value /= &p; + digit + }); + let top_quotient_big = value; + + // Load each digit witness. + let digit_witnesses = + array::from_fn(|idx| ctx.load_witness(biguint_to_fe(&digit_witnesses_big[idx]))); + + // Load top quotient witness. + let top_quotient = ctx.load_witness(biguint_to_fe(&top_quotient_big)); + (digit_witnesses, top_quotient) +} + +fn constrain_base_baby_bear_decomposition( + ctx: &mut Context, + gate: &impl GateInstructions, + range: &impl RangeInstructions, + packed: AssignedValue, + digit_witnesses: [AssignedValue; NUM_SAMPLES_PER_WORD], + top_quotient: AssignedValue, + bounds: &BaseBabyBearDecompBounds, +) -> [BabyBearWire; NUM_SAMPLES_PER_WORD] { + let p = BigUint::from(BABY_BEAR_MODULUS_U64); + let one = BigUint::from(1u64); + + for &digit in &digit_witnesses { + range.check_less_than_safe(ctx, digit, BABY_BEAR_MODULUS_U64); + } + let top_quotient_valid = + range.is_big_less_than_safe(ctx, top_quotient, bounds.top_quotient_max_plus_one.clone()); + gate.assert_is_const(ctx, &top_quotient_valid, &Fr::ONE); + + // Verify recomposition: lower = sum(digit_i * p^i) + let lower = gate.inner_product( + ctx, + digit_witnesses.iter().copied(), + iter::successors(Some(one), |power| Some(power * &p)) + .take(NUM_SAMPLES_PER_WORD) + .map(|power| QuantumCell::Constant(biguint_to_fe(&power))), + ); + + // packed == top_quotient * p^k + lower + let recomposed = gate.mul_add( + ctx, + top_quotient, + QuantumCell::Constant(biguint_to_fe(&bounds.pow_k)), + lower, + ); + ctx.constrain_equal(&packed, &recomposed); + + // Boundary check: when top_quotient is at max, lower must not exceed the remainder. + let at_top_boundary = gate.is_equal( + ctx, + top_quotient, + QuantumCell::Constant(bounds.top_quotient_max_fe), + ); + // Range-check lower against p^k (not lower_max_plus_one) because lower can be + // any value in [0, p^k - 1] and p^k may need more bits than lower_max_plus_one. + // Using is_big_less_than_safe with lower_max_plus_one would derive an insufficient + // range_bits from lower_max_plus_one.bits() (e.g. 152 vs the 155 bits needed). + let lower_range_bits = + (bounds.pow_k.bits() as usize).div_ceil(range.lookup_bits()) * range.lookup_bits(); + range.range_check(ctx, lower, lower_range_bits); + let lower_is_valid = range.is_less_than( + ctx, + lower, + QuantumCell::Constant(biguint_to_fe(&bounds.lower_max_plus_one)), + lower_range_bits, + ); + let lower_is_invalid = gate.not(ctx, lower_is_valid); + let lower_violation = gate.mul(ctx, at_top_boundary, lower_is_invalid); + gate.assert_is_const(ctx, &lower_violation, &Fr::ZERO); + + digit_witnesses.map(|value| BabyBearWire { + value, + max_bits: BABY_BEAR_BITS, + }) +} + +fn decompose_bn254_to_base_baby_bear_digits( + ctx: &mut Context, + baby_bear: &BabyBearChip, + packed: AssignedValue, +) -> [BabyBearWire; NUM_SAMPLES_PER_WORD] { + let bounds = base_baby_bear_decomp_bounds(); + let range = baby_bear.range(); + let gate = range.gate(); + let (digit_witnesses, top_quotient) = load_base_baby_bear_decomposition_witness(ctx, packed); + constrain_base_baby_bear_decomposition( + ctx, + gate, + range, + packed, + digit_witnesses, + top_quotient, + bounds, + ) +} + +#[derive(Clone, Debug)] +pub struct DigestWire { + pub elems: [AssignedValue; DIGEST_WIDTH], +} + +pub fn digest_wire_from_root(root: AssignedValue) -> DigestWire { + DigestWire { + elems: array::from_fn(|_| root), + } +} + +fn bn254_to_halo2(value: Bn254Scalar) -> Fr { + biguint_to_fe(&value.as_canonical_biguint()) +} + +/// Circuit gadget that mirrors `MultiFieldTranscript`. +/// +/// Uses absorb_idx/sample_idx sponge tracking, base-2^31 observe packing, +/// base-BabyBear sample decomposition, and direct digest absorption. +#[derive(Clone, Debug)] +pub struct TranscriptChip { + baby_bear: BabyBearChip, + sponge_state: [AssignedValue; POSEIDON2_WIDTH], + absorb_idx: usize, + sample_idx: usize, + observe_buf: Vec, + sample_buf: Vec, +} + +impl TranscriptChip { + pub fn baby_bear(&self) -> &BabyBearChip { + &self.baby_bear + } + + pub fn new(ctx: &mut Context, baby_bear: BabyBearChip) -> Self { + let zero = ctx.load_zero(); + Self { + baby_bear, + sponge_state: array::from_fn(|_| zero), + absorb_idx: 0, + sample_idx: 0, + observe_buf: Vec::with_capacity(NUM_OBS_PER_WORD), + sample_buf: Vec::with_capacity(NUM_SAMPLES_PER_WORD), + } + } + + pub fn load_digest_witness(ctx: &mut Context, digest: RootDigest) -> DigestWire { + DigestWire { + elems: array::from_fn(|i| ctx.load_witness(bn254_to_halo2(digest[i]))), + } + } + + // --- Low-level sponge (matches DuplexSponge::absorb/squeeze) --- + + fn sponge_absorb(&mut self, ctx: &mut Context, value: AssignedValue) { + self.sponge_state[self.absorb_idx] = value; + self.absorb_idx += 1; + if self.absorb_idx == POSEIDON2_RATE { + self.permute_state(ctx); + self.absorb_idx = 0; + self.sample_idx = POSEIDON2_RATE; + } + } + + fn sponge_squeeze(&mut self, ctx: &mut Context) -> AssignedValue { + if self.absorb_idx != 0 || self.sample_idx == 0 { + self.permute_state(ctx); + self.absorb_idx = 0; + self.sample_idx = POSEIDON2_RATE; + } + self.sample_idx -= 1; + self.sponge_state[self.sample_idx] + } + + fn permute_state(&mut self, ctx: &mut Context) { + let gate = self.baby_bear.range().gate(); + let mut state = Poseidon2State::new(self.sponge_state); + state.permutation(ctx, gate, &POSEIDON2_PARAMS); + self.sponge_state = state.s; + } + + // --- Observe/sample buffer management --- + + // Rule: observe-side operations call `invalidate_samples`, + // sample-side operations call `flush_observe_buf`, + // cross-layer operations call both. + + fn invalidate_samples(&mut self) { + self.sample_buf.clear(); + } + + fn flush_observe_buf(&mut self, ctx: &mut Context) { + if !self.observe_buf.is_empty() { + let gate = self.baby_bear.range().gate(); + let packed = pack_base_2_31_cells(ctx, gate, &self.observe_buf); + self.sponge_absorb(ctx, packed); + self.observe_buf.clear(); + } + } + + fn absorb_digest(&mut self, ctx: &mut Context, digest: &DigestWire) { + self.invalidate_samples(); + self.flush_observe_buf(ctx); + for &elem in &digest.elems { + self.sponge_absorb(ctx, elem); + } + } + + pub fn observe(&mut self, ctx: &mut Context, value: &ReducedBabyBearWire) { + self.invalidate_samples(); + self.observe_buf.push(*value); + if self.observe_buf.len() == NUM_OBS_PER_WORD { + self.flush_observe_buf(ctx); + } + } + + pub fn observe_ext(&mut self, ctx: &mut Context, value: &ReducedBabyBearExtWire) { + for coeff in value.coeffs() { + self.observe(ctx, coeff); + } + } + + /// Absorb digest words directly into the sponge (lossless). + pub fn observe_commit(&mut self, ctx: &mut Context, digest: &DigestWire) { + self.absorb_digest(ctx, digest); + } + + pub fn sample(&mut self, ctx: &mut Context) -> BabyBearWire { + if let Some(val) = self.sample_buf.pop() { + return val; + } + self.flush_observe_buf(ctx); + let squeezed = self.sponge_squeeze(ctx); + self.sample_buf = Vec::from(decompose_bn254_to_base_baby_bear_digits( + ctx, + &self.baby_bear, + squeezed, + )); + // Reverse so pop() returns digits in order (b_0 first). + self.sample_buf.reverse(); + self.sample_buf + .pop() + .expect("sample_buf should be non-empty") + } + + pub fn sample_ext(&mut self, ctx: &mut Context) -> BabyBearExtWire { + let coeffs = array::from_fn(|_| self.sample(ctx)); + BabyBearExt4Wire(coeffs) + } + + pub fn sample_bits(&mut self, ctx: &mut Context, bits: usize) -> AssignedValue { + assert!( + bits < (u32::BITS as usize), + "sample_bits requires bits < 32: {bits}" + ); + assert!( + (1u64 << bits) < BABY_BEAR_MODULUS_U64, + "sample_bits requires (1 << bits) < modulus: bits={bits}" + ); + + let sampled = self.sample(ctx); + if bits == 0 { + return ctx.load_zero(); + } + // PERF[jpw]: we could optimize this since the divisor is a power of 2 + let range = self.baby_bear.range(); + let divisor = BigUint::from(1u64) << bits; + let (_, rem) = range.div_mod(ctx, sampled.value, divisor, BABY_BEAR_BITS); + rem + } + + /// Asserts that the PoW witness must pass. + pub fn check_witness( + &mut self, + ctx: &mut Context, + bits: usize, + witness: &ReducedBabyBearWire, + ) { + if bits == 0 { + return; + } + + self.observe(ctx, witness); + let sampled_bits = self.sample_bits(ctx, bits); + self.baby_bear + .range() + .gate() + .assert_is_const(ctx, &sampled_bits, &Fr::ZERO); + } +} + +#[cfg(test)] +pub(crate) mod tests; diff --git a/patches/openvm-static-verifier/src/transcript/tests.rs b/patches/openvm-static-verifier/src/transcript/tests.rs new file mode 100644 index 00000000..b452609f --- /dev/null +++ b/patches/openvm-static-verifier/src/transcript/tests.rs @@ -0,0 +1,281 @@ +use std::sync::Arc; + +use halo2_base::{ + gates::{ + circuit::{builder::BaseCircuitBuilder, CircuitBuilderStage}, + GateInstructions, + }, + halo2_proofs::dev::MockProver, +}; +use openvm_stark_sdk::{ + config::baby_bear_bn254_poseidon2::{ + default_transcript, BabyBearBn254Poseidon2Config as RootConfig, Bn254Scalar, + D_EF as NATIVE_EF_DEGREE, + }, + openvm_stark_backend::{ + p3_field::{BasedVectorSpace, PrimeCharacteristicRing, PrimeField64}, + FiatShamirTranscript, + }, +}; + +use super::*; +use crate::{ + config::{STATIC_VERIFIER_LOOKUP_ADVICE_COLS, STATIC_VERIFIER_NUM_ADVICE_COLS}, + field::baby_bear::{BabyBearChip, BabyBearExtChip}, + RootEF, RootF, +}; + +fn run_mock(expect_satisfied: bool, build: impl FnOnce(&mut BaseCircuitBuilder)) { + run_mock_with_lookup_bits(expect_satisfied, 16, build); +} + +fn run_mock_with_lookup_bits( + expect_satisfied: bool, + lookup_bits: usize, + build: impl FnOnce(&mut BaseCircuitBuilder), +) { + let mut builder = BaseCircuitBuilder::from_stage(CircuitBuilderStage::Mock) + .use_k(17) + .use_lookup_bits(lookup_bits) + .use_instance_columns(1); + build(&mut builder); + + let params = builder.calculate_params(Some(4096)); + assert!( + params + .num_advice_per_phase + .first() + .copied() + .unwrap_or_default() + >= STATIC_VERIFIER_NUM_ADVICE_COLS + ); + assert!( + params + .num_lookup_advice_per_phase + .first() + .copied() + .unwrap_or_default() + >= STATIC_VERIFIER_LOOKUP_ADVICE_COLS + ); + + let prover = MockProver::run(17, &builder, vec![vec![]]) + .expect("mock prover should initialize transcript gadget circuit"); + if expect_satisfied { + prover.assert_satisfied(); + } else { + assert!( + prover.verify().is_err(), + "expected transcript replay constraints to fail" + ); + } +} + +fn ext_to_u64(ext: RootEF) -> [u64; NATIVE_EF_DEGREE] { + core::array::from_fn(|i| { + >::as_basis_coefficients_slice(&ext)[i].as_canonical_u64() + }) +} + +#[test] +fn transcript_outputs_match_native_interleaved_flow() { + let observed_ext_coeffs = [5, 7, 11, 13]; + let digest = [Bn254Scalar::from_u64(0x1234_5678)]; + + // Convenience alias for trait method disambiguation. + fn fs_observe_ext(t: &mut impl FiatShamirTranscript, val: RootEF) { + FiatShamirTranscript::::observe_ext(t, val); + } + fn fs_observe_commit(t: &mut impl FiatShamirTranscript, digest: [Bn254Scalar; 1]) { + FiatShamirTranscript::::observe_commit(t, digest); + } + fn fs_sample_ext(t: &mut impl FiatShamirTranscript) -> RootEF { + FiatShamirTranscript::::sample_ext(t) + } + fn fs_sample_bits(t: &mut impl FiatShamirTranscript, bits: usize) -> u64 { + FiatShamirTranscript::::sample_bits(t, bits) + } + fn fs_check_witness( + t: &mut impl FiatShamirTranscript, + bits: usize, + witness: RootF, + ) -> bool { + FiatShamirTranscript::::check_witness(t, bits, witness) + } + + // Build transcript state up to the PoW check, then grind for a valid witness. + let build_transcript_before_pow = || { + let mut t = default_transcript(); + t.observe(RootF::from_u64(1)); + t.observe(RootF::from_u64(2)); + t.observe(RootF::from_u64(3)); + fs_observe_ext( + &mut t, + RootEF::from_basis_coefficients_fn(|i| RootF::from_u64(observed_ext_coeffs[i])), + ); + fs_observe_commit(&mut t, digest); + let _ = t.sample(); + let _ = fs_sample_ext(&mut t); + let _ = fs_sample_bits(&mut t, 17); + t + }; + let witness_for_pow = (0u64..) + .find(|&w| { + let mut t = build_transcript_before_pow(); + fs_check_witness(&mut t, 9, RootF::from_u64(w)) + }) + .expect("should find a valid PoW witness by grinding"); + + let mut native = default_transcript(); + native.observe(RootF::from_u64(1)); + native.observe(RootF::from_u64(2)); + native.observe(RootF::from_u64(3)); + fs_observe_ext( + &mut native, + RootEF::from_basis_coefficients_fn(|i| RootF::from_u64(observed_ext_coeffs[i])), + ); + fs_observe_commit(&mut native, digest); + + let expected_sample = native.sample().as_canonical_u64(); + let expected_ext = ext_to_u64(fs_sample_ext(&mut native)); + let expected_bits = fs_sample_bits(&mut native, 17) as u64; + assert!(fs_check_witness( + &mut native, + 9, + RootF::from_u64(witness_for_pow) + )); + let expected_followup = native.sample().as_canonical_u64(); + + run_mock(true, |builder| { + let range = builder.range_chip(); + let baby_bear = BabyBearChip::new(Arc::new(range.clone())); + let baby_bear_ext = BabyBearExtChip::new(baby_bear.clone()); + + let ctx = builder.main(0); + let gate = range.gate(); + + let mut transcript = TranscriptChip::new(ctx, baby_bear.clone()); + + let one = baby_bear.load_reduced_witness(ctx, RootF::from_u64(1)); + let two = baby_bear.load_reduced_witness(ctx, RootF::from_u64(2)); + let three = baby_bear.load_reduced_witness(ctx, RootF::from_u64(3)); + transcript.observe(ctx, &one); + transcript.observe(ctx, &two); + transcript.observe(ctx, &three); + + let observed_ext = + RootEF::from_basis_coefficients_fn(|i| RootF::from_u64(observed_ext_coeffs[i])); + let observed_ext = baby_bear_ext.load_reduced_witness(ctx, observed_ext); + transcript.observe_ext(ctx, &observed_ext); + + let digest_wire = TranscriptChip::load_digest_witness(ctx, digest); + transcript.observe_commit(ctx, &digest_wire); + + let sampled = transcript.sample(ctx); + gate.assert_is_const(ctx, &sampled.value, &Fr::from(expected_sample)); + + let sampled_ext = transcript.sample_ext(ctx); + for (i, coeff) in sampled_ext.0.iter().enumerate() { + gate.assert_is_const(ctx, &coeff.value, &Fr::from(expected_ext[i])); + } + + let sampled_bits = transcript.sample_bits(ctx, 17); + gate.assert_is_const(ctx, &sampled_bits, &Fr::from(expected_bits)); + + let pow_witness = baby_bear.load_reduced_witness(ctx, RootF::from_u64(witness_for_pow)); + transcript.check_witness(ctx, 9, &pow_witness); + + let followup = transcript.sample(ctx); + gate.assert_is_const(ctx, &followup.value, &Fr::from(expected_followup)); + }); +} + +#[test] +fn transcript_check_witness_zero_bits_matches_native() { + let mut native = default_transcript(); + native.observe(RootF::from_u64(99)); + let expected_first = native.sample().as_canonical_u64(); + let _ = FiatShamirTranscript::::check_witness(&mut native, 0, RootF::from_u64(7)); + let expected_second = native.sample().as_canonical_u64(); + + run_mock(true, |builder| { + let range = builder.range_chip(); + let baby_bear = BabyBearChip::new(Arc::new(range.clone())); + + let ctx = builder.main(0); + let gate = range.gate(); + + let mut transcript = TranscriptChip::new(ctx, baby_bear.clone()); + + let obs = baby_bear.load_reduced_witness(ctx, RootF::from_u64(99)); + transcript.observe(ctx, &obs); + + let first = transcript.sample(ctx); + gate.assert_is_const(ctx, &first.value, &Fr::from(expected_first)); + + let witness = baby_bear.load_reduced_witness(ctx, RootF::from_u64(7)); + transcript.check_witness(ctx, 0, &witness); + + let second = transcript.sample(ctx); + gate.assert_is_const(ctx, &second.value, &Fr::from(expected_second)); + }); +} + +#[test] +fn transcript_sample_bits_zero_matches_native() { + let mut native = default_transcript(); + native.observe(RootF::from_u64(99)); + let expected_bits = FiatShamirTranscript::::sample_bits(&mut native, 0); + assert_eq!(expected_bits, 0); + let expected_followup = native.sample().as_canonical_u64(); + + run_mock(true, |builder| { + let range = builder.range_chip(); + let baby_bear = BabyBearChip::new(Arc::new(range.clone())); + + let ctx = builder.main(0); + let gate = range.gate(); + + let mut transcript = TranscriptChip::new(ctx, baby_bear.clone()); + + let obs = baby_bear.load_reduced_witness(ctx, RootF::from_u64(99)); + transcript.observe(ctx, &obs); + + let sampled_bits = transcript.sample_bits(ctx, 0); + gate.assert_is_const(ctx, &sampled_bits, &Fr::ZERO); + + let followup = transcript.sample(ctx); + gate.assert_is_const(ctx, &followup.value, &Fr::from(expected_followup)); + }); +} + +#[test] +fn transcript_sample_bits_rejects_bits_equal_31() { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + run_mock(true, |builder| { + let range = builder.range_chip(); + let baby_bear = BabyBearChip::new(Arc::new(range.clone())); + let ctx = builder.main(0); + let mut transcript = TranscriptChip::new(ctx, baby_bear); + let _ = transcript.sample_bits(ctx, 31); + }); + })); + assert!( + result.is_err(), + "sample_bits(31) must be rejected to match backend bound semantics", + ); +} + +#[test] +fn transcript_decomp() { + run_mock_with_lookup_bits(true, 11, |builder| { + let range = builder.range_chip(); + let baby_bear = BabyBearChip::new(Arc::new(range.clone())); + + let ctx = builder.main(0); + let gate = range.gate(); + + let mut transcript = TranscriptChip::new(ctx, baby_bear.clone()); + let sample = transcript.sample(ctx); + gate.assert_is_const(ctx, &sample.value, sample.value.value()); + }); +} diff --git a/patches/openvm-static-verifier/src/utils.rs b/patches/openvm-static-verifier/src/utils.rs new file mode 100644 index 00000000..e088c4ca --- /dev/null +++ b/patches/openvm-static-verifier/src/utils.rs @@ -0,0 +1,72 @@ +#[cfg(debug_assertions)] +thread_local! { + pub(crate) static DEBUG_ASSERTS_ENABLED: std::cell::Cell = const { std::cell::Cell::new(true) }; +} + +/// Suppress debug assertions for the duration of `f`, then restore the previous state. +#[cfg(all(test, debug_assertions))] +pub(crate) fn with_debug_asserts_disabled(f: impl FnOnce() -> R) -> R { + DEBUG_ASSERTS_ENABLED.with(|cell| { + let prev = cell.get(); + cell.set(false); + let result = f(); + cell.set(prev); + result + }) +} + +#[cfg(all(test, not(debug_assertions)))] +pub(crate) fn with_debug_asserts_disabled(f: impl FnOnce() -> R) -> R { + f() +} + +/// Like `debug_assert_eq!`, but respects the thread-local disable flag. +#[cfg(debug_assertions)] +macro_rules! guarded_debug_assert_eq { + ($left:expr, $right:expr $(,)?) => { + $crate::utils::DEBUG_ASSERTS_ENABLED.with(|cell| { + if cell.get() { + assert_eq!($left, $right); + } + }); + }; + ($left:expr, $right:expr, $($arg:tt)+) => { + $crate::utils::DEBUG_ASSERTS_ENABLED.with(|cell| { + if cell.get() { + assert_eq!($left, $right, $($arg)+); + } + }); + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! guarded_debug_assert_eq { + ($($tt:tt)*) => {}; +} + +/// Like `debug_assert!`, but respects the thread-local disable flag. +#[cfg(debug_assertions)] +macro_rules! guarded_debug_assert { + ($cond:expr $(,)?) => { + $crate::utils::DEBUG_ASSERTS_ENABLED.with(|cell| { + if cell.get() { + assert!($cond); + } + }); + }; + ($cond:expr, $($arg:tt)+) => { + $crate::utils::DEBUG_ASSERTS_ENABLED.with(|cell| { + if cell.get() { + assert!($cond, $($arg)+); + } + }); + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! guarded_debug_assert { + ($($tt:tt)*) => {}; +} + +pub(crate) use guarded_debug_assert; +pub(crate) use guarded_debug_assert_eq; diff --git a/patches/openvm-static-verifier/src/wrapper.rs b/patches/openvm-static-verifier/src/wrapper.rs new file mode 100644 index 00000000..e47ceee2 --- /dev/null +++ b/patches/openvm-static-verifier/src/wrapper.rs @@ -0,0 +1,288 @@ +use std::sync::Arc; + +use halo2_base::{ + gates::circuit::CircuitBuilderStage, + halo2_proofs::{ + halo2curves::bn256::G1Affine, + plonk::keygen_pk2, + poly::{ + commitment::{CommitmentScheme, Params}, + kzg::commitment::{KZGCommitmentScheme, ParamsKZG}, + }, + }, +}; +use itertools::Itertools; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +#[cfg(feature = "evm-prove")] +use snark_verifier_sdk::snark_verifier::{ + halo2_base::halo2_proofs::plonk::VerifyingKey, loader::evm::compile_solidity, +}; +use snark_verifier_sdk::{ + halo2::aggregation::{AggregationCircuit, AggregationConfigParams, VerifierUniversality}, + CircuitExt, Snark, SHPLONK, +}; + +use crate::{ + keygen::RawEvmProof, + prover::{Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning}, +}; + +// ---- KZG params for SVK (ported from openvm-main utils.rs) ---- + +static SVK: Lazy = Lazy::new(|| { + serde_json::from_str("\"0100000000000000000000000000000000000000000000000000000000000000\"") + .unwrap() +}); + +/// Hacking because of bad interface. This is to construct a fake KZG params to pass +/// Svk (which only requires ParamsKZG.g[0]) to AggregationCircuit. +static FAKE_KZG_PARAMS: Lazy = Lazy::new(|| KZGCommitmentScheme::new_params(1)); + +pub static KZG_PARAMS_FOR_SVK: Lazy = Lazy::new(|| { + if std::env::var("RANDOM_SRS").is_ok() { + // For testing: use a random SRS + use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; + let mut rng = ChaCha20Rng::seed_from_u64(42); + let mut params = ParamsKZG::setup(23, &mut rng); + params.downsize(1); + params + } else { + build_kzg_params_for_svk(*SVK) + } +}); + +fn build_kzg_params_for_svk(g: G1Affine) -> Halo2Params { + FAKE_KZG_PARAMS.from_parts( + 1, + vec![g], + Some(vec![g]), + Default::default(), + Default::default(), + ) +} + +// ---- Halo2ParamsReader trait ---- + +/// Trait for reading Halo2 KZG parameters by degree `k`. +pub trait Halo2ParamsReader { + fn read_params(&self, k: usize) -> Arc; +} + +// ---- Wrapper types ---- + +/// `FallbackEvmVerifier` is for the raw verifier contract outputted by +/// `snark-verifier` for on-chain verification +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FallbackEvmVerifier { + pub sol_code: String, + pub artifact: EvmVerifierByteCode, +} + +/// Bytecode of a compiled EVM verifier contract. +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EvmVerifierByteCode { + pub sol_compiler_version: String, + pub sol_compiler_options: String, + #[serde_as(as = "serde_with::hex::Hex")] + pub bytecode: Vec, +} + +#[derive(Debug, Clone)] +pub struct Halo2WrapperProvingKey { + pub pinning: Halo2ProvingPinning, +} + +const MIN_ROWS: usize = 20; + +impl Halo2WrapperProvingKey { + /// Auto select k to let Wrapper circuit only have 1 advice column. + pub fn keygen_auto_tune(reader: &impl Halo2ParamsReader, dummy_snark: Snark) -> Self { + let k = Self::select_k(dummy_snark.clone()); + tracing::info!("Selected wrapper k: {k}"); + let params = reader.read_params(k); + Self::keygen(¶ms, dummy_snark) + } + + pub fn keygen(params: &Halo2Params, dummy_snark: Snark) -> Self { + let k = params.k(); + let mut circuit = + generate_wrapper_circuit_object(CircuitBuilderStage::Keygen, k as usize, dummy_snark); + circuit.calculate_params(Some(MIN_ROWS)); + let config_params = circuit.builder.config_params.clone(); + tracing::info!( + "Wrapper circuit num advice: {:?}", + config_params.num_advice_per_phase + ); + let pk = keygen_pk2(params, &circuit, false).unwrap(); + let num_pvs = circuit.instances().iter().map(|x| x.len()).collect_vec(); + Self { + pinning: Halo2ProvingPinning { + pk, + metadata: Halo2ProvingMetadata { + config_params, + break_points: circuit.break_points(), + num_pvs, + }, + }, + } + } + + #[cfg(feature = "evm-verify")] + /// A helper function for testing to verify the proof of this circuit with evm verifier. + pub fn evm_verify( + evm_verifier: &FallbackEvmVerifier, + evm_proof: &RawEvmProof, + ) -> Result { + snark_verifier_sdk::evm::evm_verify( + evm_verifier.artifact.bytecode.clone(), + vec![evm_proof.instances.clone()], + evm_proof.proof.clone(), + ) + } + + #[cfg(feature = "evm-prove")] + /// Return deployment code for EVM verifier which can verify the snark of this circuit. + pub fn generate_fallback_evm_verifier(&self, params: &Halo2Params) -> FallbackEvmVerifier { + assert_eq!( + self.pinning.metadata.config_params.k as u32, + params.k(), + "Provided params don't match circuit config" + ); + gen_evm_verifier( + params, + self.pinning.pk.get_vk(), + self.pinning.metadata.num_pvs.clone(), + ) + } + + #[cfg(feature = "evm-prove")] + pub fn prove_for_evm(&self, params: &Halo2Params, snark_to_verify: Snark) -> RawEvmProof { + let k = self.pinning.metadata.config_params.k; + let prover_circuit = self.generate_circuit_object_for_proving(k, snark_to_verify); + let mut pvs = prover_circuit.instances(); + assert_eq!(pvs.len(), 1); + let proof = snark_verifier_sdk::evm::gen_evm_proof_shplonk( + params, + &self.pinning.pk, + prover_circuit, + pvs.clone(), + ); + + RawEvmProof { + instances: pvs.pop().unwrap(), + proof, + } + } + + #[cfg(feature = "evm-prove")] + fn generate_circuit_object_for_proving( + &self, + k: usize, + snark_to_verify: Snark, + ) -> AggregationCircuit { + assert_eq!( + snark_to_verify.instances.len(), + 1, + "Snark should only have 1 instance column" + ); + assert_eq!( + self.pinning.metadata.num_pvs[0], + snark_to_verify.instances[0].len() + 12, + ); + generate_wrapper_circuit_object(CircuitBuilderStage::Prover, k, snark_to_verify) + .use_params( + self.pinning + .metadata + .config_params + .clone() + .try_into() + .unwrap(), + ) + .use_break_points(self.pinning.metadata.break_points.clone()) + } + + pub(crate) fn select_k(dummy_snark: Snark) -> usize { + let mut k = 20; + let mut first_run = true; + loop { + let mut circuit = generate_wrapper_circuit_object( + CircuitBuilderStage::Keygen, + k, + dummy_snark.clone(), + ); + circuit.calculate_params(Some(MIN_ROWS)); + assert_eq!( + circuit.builder.config_params.num_advice_per_phase.len(), + 1, + "Snark has multiple phases" + ); + if circuit.builder.config_params.num_advice_per_phase[0] == 1 { + circuit.builder.clear(); + break; + } + if first_run { + k = log2_ceil_usize( + circuit.builder.statistics().gate.total_advice_per_phase[0] + MIN_ROWS, + ); + } else { + k += 1; + } + first_run = false; + // Prevent drop warnings + circuit.builder.clear(); + } + k + } +} + +fn generate_wrapper_circuit_object( + stage: CircuitBuilderStage, + k: usize, + snark: Snark, +) -> AggregationCircuit { + let config_params = AggregationConfigParams { + degree: k as u32, + lookup_bits: k - 1, + ..Default::default() + }; + let mut circuit = AggregationCircuit::new::( + stage, + config_params, + &KZG_PARAMS_FOR_SVK, + [snark], + VerifierUniversality::None, + ); + circuit.expose_previous_instances(false); + circuit +} + +#[cfg(feature = "evm-prove")] +fn gen_evm_verifier( + params: &Halo2Params, + vk: &VerifyingKey, + num_instance: Vec, +) -> FallbackEvmVerifier { + let sol_code = snark_verifier_sdk::evm::gen_evm_verifier_sol_code::( + params, + vk, + num_instance, + ); + let byte_code = compile_solidity(&sol_code); + FallbackEvmVerifier { + sol_code, + artifact: EvmVerifierByteCode { + sol_compiler_version: "0.8.19".to_string(), + sol_compiler_options: "".to_string(), + bytecode: byte_code, + }, + } +} + +/// Compute ceil(log2(n)) for n > 0. +fn log2_ceil_usize(n: usize) -> usize { + assert!(n > 0); + (usize::BITS - (n - 1).leading_zeros()) as usize +} diff --git a/patches/openvm-static-verifier/tests/real_prover_roundtrip.rs b/patches/openvm-static-verifier/tests/real_prover_roundtrip.rs new file mode 100644 index 00000000..bd145e59 --- /dev/null +++ b/patches/openvm-static-verifier/tests/real_prover_roundtrip.rs @@ -0,0 +1,177 @@ +//! Integration: one Halo2 KZG roundtrip on a BN254 [`MixtureFixture`] proof using only +//! [`StaticVerifierCircuit::populate_verify_stark_constraints`] (no continuations public values or +//! DAG cached-commit pin). +//! +//! Full [`StaticVerifierCircuit::populate`] end-to-end is exercised in `openvm-sdk` integration +//! tests, not here. + +use std::sync::Arc; + +use halo2_base::{ + gates::circuit::{builder::BaseCircuitBuilder, CircuitBuilderStage}, + halo2_proofs::{ + halo2curves::bn256::{Bn256, G1Affine}, + plonk::{create_proof, keygen_pk, keygen_vk}, + poly::kzg::{commitment::KZGCommitmentScheme, multiopen::ProverSHPLONK}, + transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, + }, + utils::fs::gen_srs, +}; +use openvm_stark_backend::{ + p3_util::log2_ceil_usize, + proof::Proof, + test_utils::{test_system_params_small, MixtureFixture, TestFixture}, + StarkEngine, +}; +use openvm_stark_sdk::{ + config::{ + baby_bear_bn254_poseidon2::{ + BabyBearBn254Poseidon2Config as RootConfig, BabyBearBn254Poseidon2CpuEngine, + }, + baby_bear_poseidon2::Digest as InnerDigest, + }, + utils::setup_tracing, +}; +use openvm_static_verifier::{ + field::baby_bear::{BabyBearChip, BabyBearExtChip}, + log_heights_per_air_from_proof, Fr, Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning, + StaticVerifierCircuit, StaticVerifierProof, StaticVerifierShape, +}; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; + +const MIN_ROWS: usize = 20; + +fn select_k_verify_stark(circuit: &StaticVerifierCircuit, proof: &Proof) -> usize { + let mut k = 18; + let mut first_run = true; + loop { + let shape = StaticVerifierShape { + k, + lookup_bits: k - 1, + minimum_rows: MIN_ROWS, + instance_columns: 0, + }; + let mut builder = StaticVerifierCircuit::builder(CircuitBuilderStage::Keygen, &shape); + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + let _ = circuit.populate_verify_stark_constraints(ctx, &ext_chip, proof); + let params = builder.calculate_params(Some(MIN_ROWS)); + if params.num_advice_per_phase[0] == 1 { + builder.clear(); + break; + } + if first_run { + k = log2_ceil_usize(builder.statistics().gate.total_advice_per_phase[0] + MIN_ROWS); + } else { + k += 1; + } + first_run = false; + builder.clear(); + } + tracing::info!("Auto-tuned halo2 k={k} (verify-stark constraints only)"); + k +} + +fn prove_verify_stark_constraints_only( + circuit: &StaticVerifierCircuit, + params: &Halo2Params, + pinning: &Halo2ProvingPinning, + proof: &Proof, +) -> StaticVerifierProof { + let mut builder = BaseCircuitBuilder::prover( + pinning.metadata.config_params.clone(), + pinning.metadata.break_points.clone(), + ); + builder = builder.use_instance_columns(0); + + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + let _ = circuit.populate_verify_stark_constraints(ctx, &ext_chip, proof); + + let rng = ChaCha20Rng::from_seed(Default::default()); + let instances: &[&[Fr]] = &[]; + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255<_>, + _, + Blake2bWrite, G1Affine, _>, + _, + >( + params, + &pinning.pk, + &[builder], + &[instances], + rng, + &mut transcript, + ) + .expect("Halo2 proof generation should succeed"); + + StaticVerifierProof { + proof_bytes: transcript.finalize(), + public_inputs: Vec::new(), + } +} + +#[test] +#[ignore = "too slow"] +fn real_prover_keygen_prove_verify_roundtrip() { + setup_tracing(); + let system_params = test_system_params_small(2, 8, 3); + let engine: BabyBearBn254Poseidon2CpuEngine = + BabyBearBn254Poseidon2CpuEngine::new(system_params); + + let fx = MixtureFixture::standard(5, engine.config().clone()); + let (vk, proof_keygen) = fx.keygen_and_prove(&engine); + let fx_prove = MixtureFixture::standard(5, engine.config().clone()); + let (_vk_prove, proof_prove) = fx_prove.keygen_and_prove(&engine); + + let log_heights_per_air = log_heights_per_air_from_proof(&proof_keygen); + let circuit = StaticVerifierCircuit::try_new(vk, InnerDigest::default(), &log_heights_per_air) + .expect("static circuit params"); + + let k = select_k_verify_stark(&circuit, &proof_keygen); + let shape = StaticVerifierShape { + k, + lookup_bits: k - 1, + minimum_rows: MIN_ROWS, + instance_columns: 0, + }; + let params = gen_srs(k as u32); + + // keygen with verify stark constraints only + let pinning = { + let mut builder = StaticVerifierCircuit::builder(CircuitBuilderStage::Keygen, &shape); + let range = builder.range_chip(); + let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); + let ctx = builder.main(0); + let _proof_wire = circuit.populate_verify_stark_constraints(ctx, &ext_chip, &proof_keygen); + + let config_params = builder.calculate_params(Some(shape.minimum_rows)); + + let vk = keygen_vk(¶ms, &builder).expect("keygen_vk should succeed"); + let pk = keygen_pk(¶ms, vk, &builder).expect("keygen_pk should succeed"); + let break_points = builder.break_points(); + + Halo2ProvingPinning { + pk, + metadata: Halo2ProvingMetadata { + config_params, + break_points, + num_pvs: vec![0], + }, + } + }; + assert_eq!(shape.instance_columns, 0); + let halo2_proof = + prove_verify_stark_constraints_only(&circuit, ¶ms, &pinning, &proof_prove); + + assert!(StaticVerifierCircuit::verify( + ¶ms, + pinning.pk.get_vk(), + &halo2_proof + )); +} diff --git a/releases/dev/verifier/Halo2Verifier.sol b/releases/dev/verifier/Halo2Verifier.sol index a9800f7f..4bbc3540 100644 --- a/releases/dev/verifier/Halo2Verifier.sol +++ b/releases/dev/verifier/Halo2Verifier.sol @@ -76,7 +76,7 @@ mstore(0x5e0, mod(calldataload(0x540), f_q)) mstore(0x600, mod(calldataload(0x560), f_q)) mstore(0x620, mod(calldataload(0x580), f_q)) mstore(0x640, mod(calldataload(0x5a0), f_q)) -mstore(0x80, 11470383548896865094596963285747371760877142442046712558647644420409192746327) +mstore(0x80, 11566006739371173354186701383741564010490113005908415769938152364951149974803) { let x := calldataload(0x5c0) @@ -1419,8 +1419,8 @@ mstore(0x54a0, mload(0x53c0)) mstore(0x54e0, mload(0x5440)) mstore(0x5500, mload(0x5460)) success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) -mstore(0x5520, 0x0fe832b93957c31992e2d46ed2165dd2d8ab3c9bf076c7254ff56b41632c4969) - mstore(0x5540, 0x284aacc69fa0f1c51cd331318a7ab78eec74104b87a569424bdd8b3385ebeefd) +mstore(0x5520, 0x257e500dbb2967ea5472504461ae07977ef6d5de62fcf511525b87e6f7d68cee) + mstore(0x5540, 0x11faccc27c9c05fc35c3c749e048df73e499acf916d8a92cca5e161deeb41d6c) mstore(0x5560, mload(0x4ee0)) success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) mstore(0x5580, mload(0x54a0)) @@ -1455,8 +1455,8 @@ mstore(0x5820, mload(0x5740)) mstore(0x5860, mload(0x57c0)) mstore(0x5880, mload(0x57e0)) success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) -mstore(0x58a0, 0x289a66a38979069bea5696aa76d9c408823208e16c9bfe06e8e8c7ab65ced34b) - mstore(0x58c0, 0x1d310a2ef998c261d05b10a38c18919f46256afc5e8e1063691b22593b481c57) +mstore(0x58a0, 0x2f87dc4e83928f0f24643adcdc7b3a5870d40f825f7ae68fdb0a666e271dc83b) + mstore(0x58c0, 0x131e02cfd9b2e0e3514fa444fa8249666fe96703fa13a3b251e0f91f2847ec58) mstore(0x58e0, mload(0x4f60)) success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) mstore(0x5900, mload(0x5820)) @@ -1464,8 +1464,8 @@ mstore(0x5900, mload(0x5820)) mstore(0x5940, mload(0x58a0)) mstore(0x5960, mload(0x58c0)) success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) -mstore(0x5980, 0x0bc030890773e34d809fa0c09885fd47fd08053d40477964bd47914ea4fa9ca8) - mstore(0x59a0, 0x1bc6c4e5b649a5ff35b436ce387efefdb280c9f0702bfd96e08ffde45381d339) +mstore(0x5980, 0x29a06b3e9474bd210bb66653f90b2ef87bcdbc087c07bc7122b2ba508aebb556) + mstore(0x59a0, 0x1cc13bc789626d150587ee5fbda018faf2adc715ff2dc7b94427fcd3ba7b7520) mstore(0x59c0, mload(0x4f80)) success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) mstore(0x59e0, mload(0x5900)) diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin index 2a92b4ba6d42ad096d505b36778d68bfd60b3d82..d5217e27a93575a636b1a01751f6994da9f7c441 100644 GIT binary patch delta 1036 zcmZ8fYfKbZ7~MMyXhhI0jF1${NQ*#x25YR4P--E}%o>~>ab|UV+=~brwLq~y$`W=S zyKc0#%^>a)s#Vgk23UZ`>^ly|D3;Z|K#{ABWL$ig(+BSI*b(jSeli(9I0e z1GNu#A0C}{`_Qb*Yo?_R|B<@6y()huQ8d@rU!nyXr+ikP+u!fXbyi=WqOPqQYV4a- z@l9sxr99+p<=qLN5IuL=1|K+<9w-c|Ohwg`N^3A-f16`)G%c(6nbR035R0-~H{~~N z?VKKaqGH)-?3@wT)sBhv6FO?r+fH*kp8hGI6*BKmIhWVHy=)5^?HgX(*_s@Dex#cm zo85h?Ff(-RwCg*n-St&z48cw|dW)CLw@()&Sm2QTR{dWI(Ig}wh3p#y$(xAi^&+A( z#}O=ZL)JkW{}iXBD?FlC`E{QTqX4q|#+$sBP|To)_Z~Fr=xp~Y9e?WH_bLmbPx!)x z7($SA4q~JWQZOFb_Xs#auMTHMmi>Api>Z=T&%BjEM30E;ZrUy+Lkkb1V9INWixf^^ zkr88i--=1mr@rgOWWMcXWeZjKEpo0nnoGCPA3Q9uWcs5?%uA z1S(9kdcZ;m0AjuuuwQru1<7b+lJmMm#B^b297I`AITk6!Mk3}OrtXC)NNK>&X%MJ{ z223i1sgQA>nc-%$M8sx=Rogz?&o0Ky;xL2QlI`ja?0;O4TDTS*f%1X>sjIQNI-;&0 zS2uA@SY3eF#xTTM1u1|5h}hOJP--H6jtexueatCJnlhC{>?KiAfJ0LO4=I4yW8tG) z{D3z#i0xAyx**9O%zA*qA@;fAh152zJYw{*i%5Hp;z4XL9uqd?1j$`OyK2ms>c zb&5jBDygYa-ozwimqq*{`yy-+z+nVQ#s8u}!51sX9GyqUp0WyL70-^1!3T{o#c%eN zZ>+AUb*6trecE&54&~+G1sDZdoe3M1f&c7M9v=E!Le&>FioF+GL!AW~`MOhEbL~m)*3sN*A3X<+1S(06T6pnRvU5q|B!<_f|-fzx(7`Xv-odilO zxOCYtDb%3#RC^y&11r!U%8_`X(l&dvF`J+p8==|CGzc4rcGv7@PZ_+dg{O3LAV*Xus-j-qQ? z9c$?RBTL+aLt1;;s^kz$(&^%}wR^*TpV;~fl`kLYrN#QUJA9+z0|T9HTf6&cl-F!` zCZT5G+nRIti?Zk@r>xHJ~yA5v5 zs_Da4nyq__Zd*Os=YBVyNBM%?8Q<~X<2ADNPwLgB-D%aM+7;pP*Yaeo{>?G%L$27D z-d>ftAv}b9uJ&5jB~pVd56w2g6RLdYp~)SK2pfk5C!}l!b=aCPN395ZQ)NTL3|m3_Oes zffOPGKkC4!BY?b&YNU({$!}Qs7EliUKZcsjA!>4fAS$j_I*bogrS7C=rDb4{5d>L5 z!1BkL;|v4Mh{_+6x>(+e1&FAUprGEN;xfFPC<2=-0XsASMD6oOggOtf`_mz+RkA58 zFSsyu0hK}2Ezu242XW^fHJVOOqDDj)qI@i`;^Fv4B+(AdBE}>BtS$wQab^=$yZnEF zT17{06C@x={^&h8Xb+;Nv%DyV2$DgTCb(l~AiA8xE1)x84<0$%QsgKvuE?7mW9r{v tn76jGlFO|>)6#Fr%Ii&iRlvE(oYI?b%Y5&1tBWeib`-AF>8I(I`~{}wfYty2 diff --git a/releases/dev/verifier/verifier.sol b/releases/dev/verifier/verifier.sol index d107eb59..cb68597d 100644 --- a/releases/dev/verifier/verifier.sol +++ b/releases/dev/verifier/verifier.sol @@ -21,10 +21,16 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { /// @dev The length of the proof data, in bytes. uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32; - /// @dev The length of the public values, in bytes. This value is set by - /// OpenVM and is guaranteed to be no larger than 8192. + /// @dev The number of public value limbs exposed by the Halo2 circuit. + /// This value is set by OpenVM and is guaranteed to be no larger than 8192. uint256 private constant PUBLIC_VALUES_LENGTH = 32; + /// @dev The byte width of each public value limb (1 for rv32, 2 for rv64). + uint256 private constant PUBLIC_VALUES_LIMB_SIZE = 2; + + /// @dev The total byte length of the public values payload. + uint256 private constant PUBLIC_VALUES_BYTE_LENGTH = PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE; + /// @dev The length of the full proof, in bytes uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32; @@ -38,10 +44,11 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { /// proof[..12 * 32]: KZG accumulator /// proof[12 * 32..13 * 32]: app exe commit /// proof[13 * 32..14 * 32]: app vm commit - /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValues[0..PUBLIC_VALUES_LENGTH] + /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] /// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix /// - /// @param publicValues The PVs revealed by the OpenVM guest program. + /// @param publicValues The PVs revealed by the OpenVM guest program. Each + /// public-value limb occupies PUBLIC_VALUES_LIMB_SIZE bytes in little-endian. /// @param proofData All components of the proof except the public values and /// app exe and vm commits. The expected format is: /// `abi.encodePacked(kzgAccumulator, proofSuffix)` @@ -49,7 +56,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { /// is being verified. /// @param appVmCommit The commitment to the VM configuration. function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { - if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length); + if (publicValues.length != PUBLIC_VALUES_BYTE_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_BYTE_LENGTH, publicValues.length); if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length); // We will format the public values and construct the full proof payload @@ -98,7 +105,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { // proof[..0x180]: KZG accumulator // proof[0x180..0x1a0]: app exe commit // proof[0x1a0..0x1c0]: app vm commit - // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH] + // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] // proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix /// @solidity memory-safe-assembly @@ -124,11 +131,23 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) - // Copy each byte of the public values into the proof. It copies the - // most significant bytes of public values first. - let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) + // Copy each public-value limb into the low bytes of the corresponding + // Fr slot. user_public_values stores limbs in little-endian, but each + // 32-byte word is interpreted by the EVM as big-endian, so we reverse + // the limb bytes as we copy them to the end of the word. for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) + let wordPtr := add(proofPtr, add(0x1c0, shl(5, i))) + // Clear the full word first; only the low bytes are overwritten. + mstore(wordPtr, 0) + for { let j := 0 } iszero(eq(j, PUBLIC_VALUES_LIMB_SIZE)) { j := add(j, 1) } { + // publicValues[i*LIMB_SIZE + j] is copied to the j-th byte + // from the end of the word, i.e. wordPtr + (0x1f - j). + calldatacopy( + add(wordPtr, sub(0x1f, j)), + add(publicValues.offset, add(mul(i, PUBLIC_VALUES_LIMB_SIZE), j)), + 0x01 + ) + } } } } From 475085fea592f1c074e3517c57e226deca8f088f Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 30 Jun 2026 08:58:39 +0800 Subject: [PATCH 18/19] mid --- AGENTS.md | 57 +- Cargo.lock | 15 +- Cargo.toml | 10 +- Makefile | 5 +- crates/build-guest/Cargo.toml | 1 + crates/build-guest/src/main.rs | 105 +- crates/integration/Cargo.toml | 5 + crates/integration/src/lib.rs | 86 +- crates/prover/src/prover/mod.rs | 2 + patches/openvm-sdk/Cargo.toml | 136 -- patches/openvm-sdk/contracts/.gitignore | 14 - .../contracts/abi/IOpenVmHalo2Verifier.json | 30 - patches/openvm-sdk/contracts/foundry.toml | 31 - patches/openvm-sdk/contracts/lib/.gitignore | 1 - .../contracts/src/IOpenVmHalo2Verifier.sol | 8 - .../template/OpenVmHalo2Verifier.sol | 154 -- .../contracts/test/OpenVmHalo2Verifier.t.sol | 161 -- .../contracts/test/helpers/LibString.sol | 1628 ----------------- .../contracts/test/helpers/MockDeps.sol | 12 - patches/openvm-sdk/examples/sdk_app.rs | 45 - patches/openvm-sdk/examples/sdk_evm.rs | 71 - patches/openvm-sdk/examples/sdk_stark.rs | 79 - patches/openvm-sdk/guest/fib/Cargo.toml | 17 - patches/openvm-sdk/guest/fib/openvm.toml | 3 - patches/openvm-sdk/guest/fib/src/main.rs | 40 - patches/openvm-sdk/guest/little/Cargo.toml | 25 - patches/openvm-sdk/guest/little/openvm.toml | 72 - .../openvm-sdk/guest/little/openvm_init.rs | 4 - patches/openvm-sdk/guest/little/src/main.rs | 49 - patches/openvm-sdk/guest/p256/Cargo.toml | 31 - patches/openvm-sdk/guest/p256/openvm.toml | 72 - patches/openvm-sdk/guest/p256/openvm_init.rs | 4 - patches/openvm-sdk/guest/p256/src/main.rs | 42 - patches/openvm-sdk/openvm_riscv64.toml | 3 - patches/openvm-sdk/openvm_standard.toml | 72 - patches/openvm-sdk/programs/Cargo.toml | 23 - .../programs/examples/fibonacci.elf | Bin 49008 -> 0 bytes .../openvm-sdk/programs/examples/fibonacci.rs | 21 - .../programs/examples/verify-many.elf | Bin 139992 -> 0 bytes .../programs/examples/verify-many.rs | 33 - .../programs/examples/verify-stark.elf | Bin 141928 -> 0 bytes .../programs/examples/verify-stark.rs | 30 - patches/openvm-sdk/src/builder.rs | 562 ------ patches/openvm-sdk/src/compiled.rs | 66 - patches/openvm-sdk/src/config.rs | 112 -- patches/openvm-sdk/src/error.rs | 32 - patches/openvm-sdk/src/fs.rs | 217 --- patches/openvm-sdk/src/halo2_params.rs | 59 - patches/openvm-sdk/src/keygen/dummy.rs | 149 -- patches/openvm-sdk/src/keygen/mod.rs | 139 -- patches/openvm-sdk/src/keygen/perm.rs | 93 - .../openvm-sdk/src/keygen/static_verifier.rs | 70 - patches/openvm-sdk/src/lib.rs | 882 --------- patches/openvm-sdk/src/prover/agg.rs | 484 ----- patches/openvm-sdk/src/prover/app.rs | 209 --- .../openvm-sdk/src/prover/deferral/circuit.rs | 162 -- .../openvm-sdk/src/prover/deferral/merkle.rs | 65 - patches/openvm-sdk/src/prover/deferral/mod.rs | 264 --- .../src/prover/deferral/verify_stark.rs | 116 -- patches/openvm-sdk/src/prover/evm.rs | 127 -- patches/openvm-sdk/src/prover/halo2.rs | 56 - patches/openvm-sdk/src/prover/mod.rs | 22 - patches/openvm-sdk/src/prover/root.rs | 238 --- patches/openvm-sdk/src/prover/stark.rs | 196 -- patches/openvm-sdk/src/prover/vm/mod.rs | 27 - patches/openvm-sdk/src/prover/vm/types.rs | 18 - patches/openvm-sdk/src/solidity.rs | 283 --- patches/openvm-sdk/src/stdin.rs | 86 - patches/openvm-sdk/src/tests.rs | 843 --------- patches/openvm-sdk/src/types.rs | 502 ----- patches/openvm-sdk/src/util.rs | 23 - releases/dev/verifier/verifier.bin | Bin 19459 -> 0 bytes releases/dev/verifier/verifier.sol | 154 -- 73 files changed, 264 insertions(+), 9189 deletions(-) delete mode 100644 patches/openvm-sdk/Cargo.toml delete mode 100644 patches/openvm-sdk/contracts/.gitignore delete mode 100644 patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json delete mode 100644 patches/openvm-sdk/contracts/foundry.toml delete mode 100644 patches/openvm-sdk/contracts/lib/.gitignore delete mode 100644 patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol delete mode 100644 patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol delete mode 100644 patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol delete mode 100644 patches/openvm-sdk/contracts/test/helpers/LibString.sol delete mode 100644 patches/openvm-sdk/contracts/test/helpers/MockDeps.sol delete mode 100644 patches/openvm-sdk/examples/sdk_app.rs delete mode 100644 patches/openvm-sdk/examples/sdk_evm.rs delete mode 100644 patches/openvm-sdk/examples/sdk_stark.rs delete mode 100644 patches/openvm-sdk/guest/fib/Cargo.toml delete mode 100644 patches/openvm-sdk/guest/fib/openvm.toml delete mode 100644 patches/openvm-sdk/guest/fib/src/main.rs delete mode 100644 patches/openvm-sdk/guest/little/Cargo.toml delete mode 100644 patches/openvm-sdk/guest/little/openvm.toml delete mode 100644 patches/openvm-sdk/guest/little/openvm_init.rs delete mode 100644 patches/openvm-sdk/guest/little/src/main.rs delete mode 100644 patches/openvm-sdk/guest/p256/Cargo.toml delete mode 100644 patches/openvm-sdk/guest/p256/openvm.toml delete mode 100644 patches/openvm-sdk/guest/p256/openvm_init.rs delete mode 100644 patches/openvm-sdk/guest/p256/src/main.rs delete mode 100644 patches/openvm-sdk/openvm_riscv64.toml delete mode 100644 patches/openvm-sdk/openvm_standard.toml delete mode 100644 patches/openvm-sdk/programs/Cargo.toml delete mode 100755 patches/openvm-sdk/programs/examples/fibonacci.elf delete mode 100644 patches/openvm-sdk/programs/examples/fibonacci.rs delete mode 100755 patches/openvm-sdk/programs/examples/verify-many.elf delete mode 100644 patches/openvm-sdk/programs/examples/verify-many.rs delete mode 100644 patches/openvm-sdk/programs/examples/verify-stark.elf delete mode 100644 patches/openvm-sdk/programs/examples/verify-stark.rs delete mode 100644 patches/openvm-sdk/src/builder.rs delete mode 100644 patches/openvm-sdk/src/compiled.rs delete mode 100644 patches/openvm-sdk/src/config.rs delete mode 100644 patches/openvm-sdk/src/error.rs delete mode 100644 patches/openvm-sdk/src/fs.rs delete mode 100644 patches/openvm-sdk/src/halo2_params.rs delete mode 100644 patches/openvm-sdk/src/keygen/dummy.rs delete mode 100644 patches/openvm-sdk/src/keygen/mod.rs delete mode 100644 patches/openvm-sdk/src/keygen/perm.rs delete mode 100644 patches/openvm-sdk/src/keygen/static_verifier.rs delete mode 100644 patches/openvm-sdk/src/lib.rs delete mode 100644 patches/openvm-sdk/src/prover/agg.rs delete mode 100644 patches/openvm-sdk/src/prover/app.rs delete mode 100644 patches/openvm-sdk/src/prover/deferral/circuit.rs delete mode 100644 patches/openvm-sdk/src/prover/deferral/merkle.rs delete mode 100644 patches/openvm-sdk/src/prover/deferral/mod.rs delete mode 100644 patches/openvm-sdk/src/prover/deferral/verify_stark.rs delete mode 100644 patches/openvm-sdk/src/prover/evm.rs delete mode 100644 patches/openvm-sdk/src/prover/halo2.rs delete mode 100644 patches/openvm-sdk/src/prover/mod.rs delete mode 100644 patches/openvm-sdk/src/prover/root.rs delete mode 100644 patches/openvm-sdk/src/prover/stark.rs delete mode 100644 patches/openvm-sdk/src/prover/vm/mod.rs delete mode 100644 patches/openvm-sdk/src/prover/vm/types.rs delete mode 100644 patches/openvm-sdk/src/solidity.rs delete mode 100644 patches/openvm-sdk/src/stdin.rs delete mode 100644 patches/openvm-sdk/src/tests.rs delete mode 100644 patches/openvm-sdk/src/types.rs delete mode 100644 patches/openvm-sdk/src/util.rs delete mode 100644 releases/dev/verifier/verifier.bin delete mode 100644 releases/dev/verifier/verifier.sol diff --git a/AGENTS.md b/AGENTS.md index 4a3a02cd..f644c7c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ Critical context for AI agents working on this repo. Read this before making cha ## OpenVM Version Sensitivity -This project uses **OpenVM v2.0.0-beta.2** as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: +This project uses **OpenVM v2.0.0-beta.2** on the `develop-v2.1.0-rv64` branch as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: - The guest/host data layout (hint streams, public inputs) - The Halo2 SRS degree requirement @@ -23,13 +23,13 @@ This project uses **OpenVM v2.0.0-beta.2** as its ZKVM. Guest executables (`.vme ### How to update OpenVM dependencies correctly -OpenVM is declared as a **git dependency** (`branch = "develop-v2.1.0-rvr"`) in `Cargo.toml`, but the exact commit is pinned in `Cargo.lock`. Running a bare `cargo update` will **not** move the git branch forward; instead it will only bump unrelated crates.io packages (e.g. `alloy`, `revm`) which often break compatibility with the `scroll-tech/reth` and `sbv` forks. +OpenVM is declared as a **git dependency** (`branch = "develop-v2.1.0-rv64"`) in `Cargo.toml`, but the exact commit is pinned in `Cargo.lock`. Running a bare `cargo update` will **not** move the git branch forward; instead it will only bump unrelated crates.io packages (e.g. `alloy`, `revm`) which often break compatibility with the `scroll-tech/reth` and `sbv` forks. **Do NOT run a global `cargo update` unless you are prepared to upgrade the entire `alloy`/`revm`/`reth`/`sbv` dependency chain together.** To check whether the branch actually has new commits: ```bash -git ls-remote https://github.com/openvm-org/openvm.git develop-v2.1.0-rvr +git ls-remote https://github.com/openvm-org/openvm.git develop-v2.1.0-rv64 ``` If the returned SHA differs from the one recorded in `Cargo.lock`, update only the OpenVM packages: ```bash @@ -41,7 +41,7 @@ Then rebuild guests and run tests as described below. 1. **Update the hardcoded version string** in `crates/build-guest/src/verifier.rs`: ```rust - let openvm_version = "v2.1.0"; // MUST match openvm-solidity-sdk tag + let openvm_version = "v2.0"; // MUST match the OPENVM_VERSION constant in the generated verifier.sol ``` 2. **Force-rebuild ALL guest assets** (auto mode skips existing files): @@ -54,6 +54,12 @@ Then rebuild guests and run tests as described below. > `RECOMPUTE_MODE=yes` is **required** to regenerate the EVM verifier bytecode. > Without it the build only downloads the Solidity source, producing an empty > bytecode file that will cause `verify_evm_proof` to fail. + > + > The build also **post-processes** the upstream `OpenVmHalo2Verifier.sol` for + > rv64 public-value limbs and then **recompiles** the post-processed Solidity + > with `solc` to produce `verifier.bin`. If `solc` is missing or the + > post-processing cannot be applied, the build will fail instead of producing + > a broken `verifier.bin`. 3. **Verify commitments were updated** — check that `*_exe_commit.rs` and `*_vm_commit.rs` files changed, and that `openVmVk.json` timestamps are fresh. @@ -73,6 +79,11 @@ Then rebuild guests and run tests as described below. ``` Integration tests reuse cached proofs by default. Stale proofs from a previous OpenVM version will cause failures. +### Patches + +- **`openvm-sdk` is intentionally NOT patched.** The upstream crate is used directly. rv64-specific handling of the generated EVM verifier is done at application level in `crates/build-guest`. +- **`openvm-static-verifier` IS patched** (`patches/openvm-static-verifier/`). The patch disables forwarding of `snark-verifier-sdk/cuda`, which keeps the final Halo2 SNARK step on CPU while OpenVM STARK proving uses the GPU backend. On the RTX 3090 (24 GB) machines used for development, the upstream GPU Halo2 SNARK prover exhausts GPU memory after OpenVM STARK proving; the first visible symptom is a `cudaErrorInvalidConfiguration` from halo2-gpu's quotient kernel. The split-process `prover-split` binary works around the memory pressure by giving the bundle SNARK step a fresh CUDA context. + ## Common Failure Patterns ### `NativeHintSliceSubEx` assertion failure @@ -95,17 +106,41 @@ This happens when: - The verifier was built **without** `RECOMPUTE_MODE=yes` (uses `Sdk::riscv32()` default) - The verifier was built **without** the deferral prover, but the proof uses deferral (batch/bundle) - The verifier's `AggregationTreeConfig` does not match the prover's (`num_children_internal/leaf`) +- `verifier.bin` is stale and was **not** recompiled from the post-processed `verifier.sol` **Fix**: Regenerate with: ```bash RECOMPUTE_MODE=yes cargo run --release -p scroll-zkvm-build-guest -- --mode force ``` +### `InvalidPublicValuesLength` (Solidity error `0x604a5115`) +**Cause**: `verifier.bin` still expects rv32 public values (32 bytes), but the proof carries rv64 public-value limbs (64 bytes). This happens when the post-processed `verifier.sol` was written but the bytecode in `verifier.bin` was not recompiled from it. + +**Fix**: Regenerate as above; the build-guest now recompiles `verifier.sol` with `solc` automatically. + +### `cudaErrorInvalidConfiguration` in halo2-gpu quotient kernel +**Cause**: GPU memory exhaustion during the final Halo2 SNARK step. OpenVM STARK proving on the same GPU leaves less than halo2-gpu's hardcoded 256 MiB reserve, so `query_device_free_bytes_for_chunking()` returns `0`. `_halo2_evaluate_h_max_rows` then returns a `batch_size` of `0`, the quotient kernel is launched with `num_blocks=0`, and CUDA reports `cudaErrorInvalidConfiguration` (`cuda/src/quotient.cu:698`). This is a memory-capacity failure, not a kernel code bug; bypassing the reserve only moves the failure to a later SNARK stage (e.g., `InsufficientGpuMemory` in `extended_from_lagrange_vec_device` or `pk.fixed_values_device()`). + +**Fix**: The default `test-e2e-bundle` path now spawns a dedicated `prover-split` subprocess for the bundle STARK + SNARK steps. The subprocess gets a fresh CUDA context, so it is no longer limited by the memory left over from chunk/batch STARK proving. Keep the `openvm-static-verifier` patch in place so the SNARK step runs on CPU; this combination has been verified to pass on an RTX 3090 (24 GB). To disable the subprocess and run in-process, set `SCROLL_ZKVM_SPLIT_STARK_SNARK=0`. + ### `cargo update` breaks compilation with alloy/revm type mismatches **Symptoms**: Errors like `missing verify_and_compute_signer_unchecked in implementation` (alloy) or `mismatched types` between `revm_primitives::hardfork::SpecId` and `SpecId` (revm). **Cause**: A global `cargo update` bumps `alloy` to 1.8.x and `revm` to 30.2.0, but the `scroll-tech/reth` and `sbv` forks were built against older versions. The `[patch.crates-io]` table pins `revm` to `scroll-v91` (30.1.1), which no longer satisfies the newer `alloy-evm` requirements, leading to duplicate registry versions of `revm-handler` / `revm-primitives` in the dependency graph. **Fix**: Restore the original `Cargo.lock` (`git checkout HEAD -- Cargo.lock`) and update only what you actually need (e.g. `cargo update -p openvm`). +### `cudaErrorInvalidConfiguration` / `InsufficientGpuMemory` persists after tuning +If you are trying to remove the `openvm-static-verifier` patch and run the upstream GPU Halo2 SNARK on a 24 GB GPU, the following parameter changes were investigated and **did not resolve** the memory exhaustion: + +| Tuning attempt | Why it was tried | Result | +|----------------|------------------|--------| +| `AggregationTreeConfig {2,2}` | Smaller fan-out should reduce per-aggregation-step memory | Static-verifier circuit size stayed ~26 M advice cells; same `cudaErrorInvalidConfiguration` failure | +| `segmentation_max_memory` capped at 8 GiB / 2 GiB | Smaller RV64 segments should lower peak STARK memory | No meaningful reduction in per-segment trace size; 2 GiB cap changed failure mode to `InsufficientGpuMemory` but still OOMed | +| Lower WHIR security bits on root params (e.g. 80-bit) | Fewer WHIR queries shrink the static-verifier circuit | Rejected — lowers provable security | + +**Conclusion:** On the current OpenVM v2 100-bit-security configuration, the bundle SNARK wrapper circuit is ~26 M Halo2 advice cells. Running STARK and SNARK in the same process leaves the GPU with too little memory for the upstream GPU SNARK prover. The repository now implements a split-process path (`prover-split`) that runs the bundle STARK + SNARK in a fresh CUDA context. With the `openvm-static-verifier` patch (CPU SNARK), this passes on an RTX 3090 (24 GB). + +Removing the `openvm-static-verifier` patch to re-enable GPU SNARK was also tested in the split-process subprocess. It still fails with `InsufficientGpuMemory { context: "plonk::prover: pk.fixed_values_device() unavailable", free_bytes: 0 }`, which means the upstream GPU Halo2 SNARK prover itself needs more than 24 GB for this circuit even with a clean CUDA context. Therefore the static-verifier patch is still required on 24 GB GPUs; a GPU with significantly more VRAM would be needed to remove it. + ### Docker build fails with stale CID The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. Use local build (`cargo run -p scroll-zkvm-build-guest`) as fallback. @@ -127,6 +162,16 @@ The Makefile sets `RUST_MIN_STACK=16777216` (16 MB) and `CARGO_CONFIG_FLAG`. Run - Stack overflow during prover initialization (default Rust stack is only ~2 MB) - Missing CUDA features if `GPU=1` is set but `--features scroll-zkvm-integration/cuda` is not passed +### GPU device selection + +OpenVM's CUDA backend initializes a process-wide memory manager on the device that is active when it first allocates. Switching CUDA devices inside the same process after STARK objects have been created breaks that global state (allocations/frees start failing with `cudaErrorInvalidValue`). + +To run OpenVM on a specific GPU, set the device **before the process starts**: +```bash +CUDA_VISIBLE_DEVICES=1 GPU=1 make test-e2e-bundle +``` +Do not attempt to switch devices from within Rust code. + ## Deferral Model (OpenVM v2+) OpenVM v2 replaces the traditional root-verifier recursion with a **deferred compute model**: @@ -141,7 +186,7 @@ The extra 2 AIRs in batch/bundle come from the deferral extension. | Parameter | Prover (`crates/prover/src/prover/mod.rs`) | Verifier (`crates/build-guest/src/main.rs`) | |-----------|---------------------------------------------|---------------------------------------------| -| `AggregationTreeConfig` | `num_children_internal: 2, num_children_leaf: 2` | Same | +| `AggregationTreeConfig` | `num_children_internal: 3, num_children_leaf: 4` | Same | | `DeferralProver` | Built from child SDK in `enable_deferral()` | Built from batch SDK in `generate_evm_verifier()` | | `agg_params` | `leaf_params + internal_params` (100-bit security) | Same | @@ -154,6 +199,8 @@ If any of these mismatch, the EVM verifier will reject proofs with `ProofVerific | `releases/dev/{chunk,batch,bundle}/app.vmexe` | Guest executables | | `releases/dev/verifier/openVmVk.json` | Program commitments loaded by integration tests | | `releases/dev/verifier/verifier.bin` | EVM verifier bytecode | +| `releases/dev/verifier/halo2_pk.bin` | Serialized Halo2 proving key used by `prover-split` | +| `crates/integration/src/bin/prover-split.rs` | Subprocess binary for bundle STARK + SNARK proving | | `crates/circuits/*-circuit/openvm.toml` | Guest VM configs (FRI params, PoW bits) | | `crates/circuits/*-circuit/commitments.rs` | Hardcoded commitment arrays | | `~/.openvm/params/kzg_bn254_24.srs` | Halo2 KZG SRS (2 GB) | diff --git a/Cargo.lock b/Cargo.lock index 887f5220..8da601a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -769,7 +769,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -780,7 +780,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2357,7 +2357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -3850,7 +3850,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5090,6 +5090,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0-beta.2" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0-rv64#46277f7a30633b801f9007194284e5cc16763c8a" dependencies = [ "alloy-sol-types", "bitcode", @@ -7703,7 +7704,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -8026,6 +8027,7 @@ dependencies = [ "openvm-stark-sdk", "openvm-static-verifier", "openvm-verify-stark-circuit", + "regex", "scroll-zkvm-types", "serde_json", "snark-verifier-sdk", @@ -8075,6 +8077,7 @@ dependencies = [ "alloy-rpc-client", "alloy-transport", "base64", + "bincode 1.3.3", "bincode 2.0.1", "bytesize", "cargo_metadata 0.23.1", @@ -8938,7 +8941,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 46e7fbb4..2d7c857c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -178,11 +178,11 @@ inherits = "profiling" # Patch openvm-static-verifier so its `cuda` feature does not forward # `snark-verifier-sdk/cuda`. This keeps OpenVM STARK proving on GPU while -# forcing the final Halo2 SNARK step onto CPU (the GPU prover fails with -# `cudaErrorInvalidConfiguration` on this machine). +# forcing the final Halo2 SNARK step onto CPU (the upstream GPU prover fails +# with `cudaErrorInvalidConfiguration` in halo2-gpu's quotient kernel on this +# machine). # -# Also patch openvm-sdk so the EVM verifier template receives the public-values -# length in bytes (rv64 cells are 2 bytes), not in cell count. +# openvm-sdk is intentionally NOT patched; rv64 public-value limb handling is +# done by application-level post-processing of the generated verifier.sol. [patch."https://github.com/openvm-org/openvm.git"] openvm-static-verifier = { path = "patches/openvm-static-verifier" } -openvm-sdk = { path = "patches/openvm-sdk" } diff --git a/Makefile b/Makefile index b3e0fff1..76b7f15b 100644 --- a/Makefile +++ b/Makefile @@ -105,5 +105,8 @@ test-bundle: test-bundle-local: @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test bundle_circuit setup_prove_verify_local_task -- --exact --nocapture -test-e2e-bundle: +build-prover-split: + cargo build --release --bin prover-split $(CARGO_CONFIG_FLAG) + +test-e2e-bundle: build-prover-split @cargo test $(CARGO_CONFIG_FLAG) --release -p scroll-zkvm-integration --test bundle_circuit e2e -- --exact --nocapture diff --git a/crates/build-guest/Cargo.toml b/crates/build-guest/Cargo.toml index fc00af7a..67979736 100644 --- a/crates/build-guest/Cargo.toml +++ b/crates/build-guest/Cargo.toml @@ -25,6 +25,7 @@ toml.workspace = true cargo_metadata.workspace = true dotenvy.workspace = true clap = { version = "4.0", features = ["derive"] } +regex = "1.11" [features] default = ["scroll"] diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index d9215d1b..c173317a 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -34,6 +34,7 @@ use clap::{Parser, ValueEnum}; use dotenvy::dotenv; use eyre::Result; +use serde_json::json; use openvm_build::GuestOptions; use openvm_instructions::exe::VmExe; use openvm_circuit::arch::instructions::DEFERRAL_AS; @@ -46,7 +47,7 @@ use openvm_sdk::{ use openvm_sdk_config::SdkVmConfig; use openvm_stark_sdk::{ config::{app_params_with_100_bits_security, internal_params_with_100_bits_security, leaf_params_with_100_bits_security, root_params_with_100_bits_security}, - openvm_stark_backend::p3_field::PrimeField32, + openvm_stark_backend::{codec::Encode, p3_field::PrimeField32}, }; use openvm_continuations::CommitBytes; use openvm_deferral_circuit::DeferralFn; @@ -59,11 +60,14 @@ use openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine as use scroll_zkvm_types::zkvm::AGG_STARK_PROVING_KEY; use std::{ env, fs, + io::Write, path::{Path, PathBuf}, + process::{Command, Stdio}, sync::Arc, time::Instant, }; +mod post_process; mod verifier; const DIGEST_SIZE: usize = 8; @@ -473,15 +477,110 @@ fn generate_evm_verifier( } // Backwards-compatible names used by the Rust verifier. - fs::write(&path_verifier_sol, &verifier.openvm_verifier_code)?; + // OpenVM upstream emits an rv32-oriented wrapper. Post-process it so the + // on-chain verifier understands rv64's 2-byte little-endian public-value + // limbs. This avoids patching openvm-sdk itself. + let openvm_verifier_code = + post_process::post_process_openvm_verifier_for_rv64(&verifier.openvm_verifier_code)?; + fs::write(&path_verifier_sol, openvm_verifier_code)?; println!("{LOG_PREFIX} verifier_sol (OpenVmHalo2Verifier) written to {path_verifier_sol:?}"); - fs::write(&path_verifier_bin, &verifier.artifact.bytecode)?; + // OpenVM SDK compiled the wrapper before we post-processed it, so the + // artifact bytecode still expects rv32 public values. Recompile the + // post-processed verifier.sol with the same solc settings to obtain an + // rv64-aware bytecode. + let verifier_bytecode = compile_post_processed_verifier_bytecode(verifier_output_dir)?; + fs::write(&path_verifier_bin, verifier_bytecode)?; println!("{LOG_PREFIX} verifier_bin written to {path_verifier_bin:?}"); + // Persist the Halo2 proving key so the SNARK step can run in a separate + // process with a fresh CUDA context (no OpenVM STARK GPU state). + let halo2_pk = sdk.halo2_pk(); + let halo2_pk_bytes = halo2_pk.encode_to_vec()?; + let path_halo2_pk = verifier_output_dir.join("halo2_pk.bin"); + fs::write(&path_halo2_pk, halo2_pk_bytes)?; + println!("{LOG_PREFIX} halo2_pk written to {path_halo2_pk:?}"); + Ok(()) } +/// Compile the post-processed rv64 `verifier.sol` (and its imports) with the +/// same solc settings OpenVM SDK uses internally. Returns the raw deployment +/// bytecode for the `OpenVmHalo2Verifier` contract. +fn compile_post_processed_verifier_bytecode(verifier_output_dir: &Path) -> Result> { + let interface = fs::read_to_string( + verifier_output_dir + .join("interfaces") + .join("IOpenVmHalo2Verifier.sol"), + )?; + let halo2_verifier = fs::read_to_string(verifier_output_dir.join("Halo2Verifier.sol"))?; + let openvm_verifier = fs::read_to_string(verifier_output_dir.join("verifier.sol"))?; + + // Matches the solc invocation in openvm_sdk::solidity::generate_halo2_verifier_solidity. + let solc_input = json!({ + "language": "Solidity", + "sources": { + "src/v2.0/interfaces/IOpenVmHalo2Verifier.sol": { "content": interface }, + "src/v2.0/Halo2Verifier.sol": { "content": halo2_verifier }, + "src/v2.0/OpenVmHalo2Verifier.sol": { "content": openvm_verifier } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 100000, + "details": { "constantOptimizer": false, "yul": false } + }, + "evmVersion": "paris", + "viaIR": false, + "outputSelection": { "*": { "*": ["evm.bytecode.object"] } } + } + }); + + let mut child = Command::new("solc") + .arg("--standard-json") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("Failed to spawn solc"); + + child + .stdin + .take() + .unwrap() + .write_all(solc_input.to_string().as_bytes())?; + let output = child.wait_with_output()?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(eyre::eyre!("solc failed: {stderr}")); + } + + let parsed: serde_json::Value = serde_json::from_slice(&output.stdout)?; + if let Some(errors) = parsed.get("errors") { + for err in errors.as_array().unwrap_or(&vec![]) { + if err.get("severity").and_then(|s| s.as_str()) == Some("error") { + return Err(eyre::eyre!("solc error: {err}")); + } + } + } + + let bytecode_hex = parsed + .get("contracts") + .and_then(|c| c.get("src/v2.0/OpenVmHalo2Verifier.sol")) + .and_then(|c| c.get("OpenVmHalo2Verifier")) + .and_then(|c| c.get("evm")) + .and_then(|c| c.get("bytecode")) + .and_then(|c| c.get("object")) + .and_then(|s| s.as_str()) + .ok_or_else(|| { + eyre::eyre!("failed to extract OpenVmHalo2Verifier bytecode from solc output") + })?; + + hex::decode(bytecode_hex) + .map_err(|e| eyre::eyre!("solc returned invalid hex bytecode: {e}")) +} + fn generate_openvm_assets( workspace_dir: &PathBuf, release_output_dir: &PathBuf, diff --git a/crates/integration/Cargo.toml b/crates/integration/Cargo.toml index a9d7fff0..0e63e782 100644 --- a/crates/integration/Cargo.toml +++ b/crates/integration/Cargo.toml @@ -11,6 +11,10 @@ path = "src/bin/chunk-benchmark.rs" name = "chunk-scanner" path = "src/bin/chunk-scanner.rs" +[[bin]] +name = "prover-split" +path = "src/bin/prover-split.rs" + [dependencies] scroll-zkvm-types.workspace = true scroll-zkvm-prover.workspace = true @@ -37,6 +41,7 @@ alloy-transport = { workspace = true, features = ["throttle"] } alloy-primitives.workspace = true base64.workspace = true bincode.workspace = true +bincode_v1.workspace = true cargo_metadata.workspace = true clap.workspace = true csv.workspace = true diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index e92519e6..122073b3 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -44,6 +44,10 @@ const FD_APP_EXE: &str = "app.vmexe"; /// Environment variable used to set the test-run's output directory for assets. const ENV_OUTPUT_DIR: &str = "OUTPUT_DIR"; +/// When set to "1", run STARK and SNARK proving in separate subprocesses so that +/// the SNARK step starts with a clean CUDA context. +const ENV_SPLIT_STARK_SNARK: &str = "SCROLL_ZKVM_SPLIT_STARK_SNARK"; + /// Enviroment settings for test: fork pub fn testing_hardfork() -> ForkName { testing_version().fork @@ -532,6 +536,80 @@ where prove_verify_single_evm_with_deferral::(prover, witness, proofs, None) } +/// Locate the `prover-split` binary used to run STARK/SNARK in separate processes. +/// The binary is expected next to the current test executable +/// (`target//prover-split`). The Makefile / CI must build it beforehand +/// (`cargo build --release --bin prover-split`). +fn prover_split_binary_path() -> eyre::Result { + let mut path = std::env::current_exe()?; + path.pop(); // deps/ + path.pop(); // / + path.push("prover-split"); + if !path.exists() { + eyre::bail!("prover-split binary not found at {path:?}; run `cargo build --release --bin prover-split` first"); + } + Ok(path) +} + +/// Generate the final EVM proof in a fresh `prover-split` subprocess. +/// +/// The parent test process already ran chunk/batch STARK proving, which leaves +/// the CUDA context with a large memory footprint. Spawning a new process for +/// the bundle STARK + SNARK steps gives the SNARK step a clean CUDA context and +/// avoids the 24 GB GPU OOM that occurs when everything runs in one process. +fn prove_evm_split( + task: &UniversalProvingTask, + def_inputs: &[DeferralInput], + def_states: &[DeferralState], + task_id: &str, +) -> eyre::Result +where + T: ProverTester, +{ + let binary = prover_split_binary_path()?; + let work_dir = DIR_TESTRUN + .get() + .ok_or(eyre::eyre!("missing testrun dir"))? + .join("split") + .join(task_id); + std::fs::create_dir_all(&work_dir)?; + + // Use bincode (not JSON) because DeferralState contains HashMap keys that + // are not valid JSON strings. + let task_file = work_dir.join("task.bin"); + let def_inputs_file = work_dir.join("def_inputs.bin"); + let def_states_file = work_dir.join("def_states.bin"); + let proof_file = work_dir.join("proof.json"); + + std::fs::write(&task_file, bincode_v1::serialize(task)?)?; + std::fs::write(&def_inputs_file, bincode_v1::serialize(def_inputs)?)?; + std::fs::write(&def_states_file, bincode_v1::serialize(def_states)?)?; + + tracing::info!("spawning EVM proof subprocess"); + let status = std::process::Command::new(&binary) + .arg("evm") + .arg("--asset-base-dir") + .arg(ASSET_BASE_DIR.as_path()) + .arg("--circuit") + .arg(T::NAME) + .arg("--task") + .arg(&task_file) + .arg("--def-inputs") + .arg(&def_inputs_file) + .arg("--def-states") + .arg(&def_states_file) + .arg("--output") + .arg(&proof_file) + .status()?; + if !status.success() { + eyre::bail!("EVM proof subprocess failed"); + } + + let proof: ProofEnum = read_json(&proof_file) + .map_err(|e| eyre::eyre!("failed to read EVM proof: {e}"))?; + Ok(proof) +} + /// End-to-end EVM proof with deferred STARK verification (v2). #[instrument(name = "prove_verify_single_evm_with_deferral", skip_all)] pub fn prove_verify_single_evm_with_deferral( @@ -581,11 +659,15 @@ where stark_proofs.into_iter(), input_commits, )?; - // Construct stark proof for the circuit. + // Construct the final EVM proof. For circuits that use deferral (bundle), + // default to a fresh subprocess so the Halo2 SNARK step starts with a clean + // CUDA context. Set SCROLL_ZKVM_SPLIT_STARK_SNARK=0 to run in-process. let proof = if def_inputs.is_empty() { prover.prove_task(&task, true)? - } else { + } else if std::env::var(ENV_SPLIT_STARK_SNARK).as_deref() == Ok("0") { prover.prove_task_with_deferral(&task, true, &def_inputs, &def_states)? + } else { + prove_evm_split::(&task, &def_inputs, &def_states, &task_id)? }; write_json(&path_proof, &proof)?; tracing::debug!(name: "cached_evm_proof", ?task_id); diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index d85258a6..84fab672 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -384,10 +384,12 @@ impl Prover { self.execute_and_check(&stdin)?; let sdk = self.get_sdk()?; + let evm_proof = sdk .prove_evm(self.app_exe.clone(), stdin, def_inputs) .map_err(|e| Error::GenProof(format!("{}", e)))?; Ok(evm_proof) } + } diff --git a/patches/openvm-sdk/Cargo.toml b/patches/openvm-sdk/Cargo.toml deleted file mode 100644 index 84f73fce..00000000 --- a/patches/openvm-sdk/Cargo.toml +++ /dev/null @@ -1,136 +0,0 @@ -[package] -name = "openvm-sdk" -version = "2.0.0-beta.2" -edition = "2021" -rust-version = "1.91.1" -authors = ["OpenVM Authors"] -homepage = "https://openvm.dev" -repository = "https://github.com/openvm-org/" -license = "MIT OR Apache-2.0" -autoexamples = false - -[dependencies] -openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false } -openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, features = ["cpu-backend"] } -openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2", default-features = false, optional = true } - -openvm-build = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } - -openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0-rv64", default-features = false } -# Point to the local patch so `openvm-static-verifier/cuda` does not enable -# `snark-verifier-sdk/cuda` (Halo2 SNARK stays on CPU). -openvm-static-verifier = { path = "../openvm-static-verifier", default-features = false, optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.5.2", default-features = false, optional = true, features = ["halo2-axiom"] } - -alloy-sol-types = { version = "1.4.1", optional = true } -forge-fmt = { git = "https://github.com/foundry-rs/foundry.git", tag = "v1.5.0", optional = true } -tempfile = { version = "3.13.0", optional = true } - -bitcode = { version = "0.6.5", default-features = false, features = ["serde"] } -cfg-if = "1.0.0" -clap = { version = "4.5.23", features = ["derive"] } -derivative = "2.2.0" -derive_more = { version = "1.0.0", features = ["display"], default-features = false } -derive-new = "0.6.0" -eyre = "0.6.12" -getset = "0.1.3" -hex = { version = "0.4.3", default-features = false } -itertools = { version = "0.14.0", default-features = false } -serde = { version = "1.0.201", default-features = false, features = ["derive"] } -serde_json = "1.0.117" -serde_with = { version = "3.11.0", features = ["hex"] } -thiserror = "1.0.65" -tracing = "0.1.40" -metrics = { version = "0.23.0", optional = true } - -[dev-dependencies] -tempfile = "3.13.0" - -[features] -default = ["parallel", "jemalloc"] -root-prover = [ - "openvm-continuations/root-prover", - "openvm-stark-sdk/baby-bear-bn254-poseidon2", - "openvm-cuda-backend?/baby-bear-bn254-poseidon2", -] -evm-prove = [ - "root-prover", - "dep:openvm-static-verifier", - "dep:halo2-base", - "openvm-static-verifier/evm-prove", -] -evm-verify = [ - "evm-prove", - "openvm-static-verifier/evm-verify", - "dep:alloy-sol-types", - "dep:tempfile", -] -# Optional Solidity code formatting; requires Rust 1.91+ due to foundry/alloy transitive deps. -evm-verify-fmt = [ - "evm-verify", - "dep:forge-fmt", -] -metrics = ["dep:metrics", "openvm-continuations/metrics", "openvm-sdk-config/metrics"] -aot = [ - "openvm-circuit/aot", - "openvm-sdk-config/aot", -] -rvr = [ - "openvm-circuit/rvr", - "openvm-sdk-config/rvr", -] -tco = [ - "openvm-circuit/tco", - "openvm-sdk-config/tco", -] -unprotected = ["openvm-circuit/unprotected"] - -# for guest profiling: -perf-metrics = [ - "openvm-circuit/perf-metrics", - "openvm-transpiler/function-span", - "openvm-sdk-config/perf-metrics" -] - -# turns on stark-backend debugger in all proofs -stark-debug = ["openvm-circuit/stark-debug"] -test-utils = ["openvm-circuit/test-utils"] - -parallel = ["openvm-continuations/parallel", "openvm-sdk-config/parallel"] -mimalloc = ["openvm-circuit/mimalloc", "openvm-sdk-config/mimalloc"] -jemalloc = ["openvm-circuit/jemalloc", "openvm-sdk-config/jemalloc"] -jemalloc-prof = ["openvm-circuit/jemalloc-prof"] - -cuda = [ - "dep:openvm-cuda-backend", - "openvm-circuit/cuda", - "openvm-sdk-config/cuda", - "openvm-continuations/cuda", - "openvm-verify-stark-circuit/cuda", - "openvm-static-verifier?/cuda", -] -cell-profiling = [ - "evm-prove", - "openvm-static-verifier/cell-profiling", -] - -[[example]] -name = "sdk_app" -path = "examples/sdk_app.rs" - -[[example]] -name = "sdk_stark" -path = "examples/sdk_stark.rs" - -[[example]] -name = "sdk_evm" -path = "examples/sdk_evm.rs" -required-features = ["evm-verify"] diff --git a/patches/openvm-sdk/contracts/.gitignore b/patches/openvm-sdk/contracts/.gitignore deleted file mode 100644 index 85198aaa..00000000 --- a/patches/openvm-sdk/contracts/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -!/broadcast -/broadcast/*/31337/ -/broadcast/**/dry-run/ - -# Docs -docs/ - -# Dotenv file -.env diff --git a/patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json b/patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json deleted file mode 100644 index 7ee1df76..00000000 --- a/patches/openvm-sdk/contracts/abi/IOpenVmHalo2Verifier.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "type": "function", - "name": "verify", - "inputs": [ - { - "name": "publicValues", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "proofData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "appExeCommit", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "appVmCommit", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [], - "stateMutability": "view" - } -] \ No newline at end of file diff --git a/patches/openvm-sdk/contracts/foundry.toml b/patches/openvm-sdk/contracts/foundry.toml deleted file mode 100644 index 1e28834e..00000000 --- a/patches/openvm-sdk/contracts/foundry.toml +++ /dev/null @@ -1,31 +0,0 @@ -[profile.default] -src = "src" -out = "out" -libs = ["lib"] -verbosity = 2 -solc = "0.8.19" -optimizer = true -optimizer_runs = 100000 -evm_version = "shanghai" -show_progress = true -fs_permissions = [{ access = "read", path = "./template"}, { access = "read", path = "./test/helpers/MockDeps.sol"}] -ffi = true - -[profile.default.optimizer_details] - constantOptimizer = false - yul = false - -[fuzz] - runs = 256 - -[fmt] - bracket_spacing = true - int_types = "long" - line_length = 120 - multiline_func_header = "attributes_first" - number_underscore = "thousands" - quote_style = "double" - single_line_statement_blocks = "single" - tab_width = 4 - wrap_comments = false - \ No newline at end of file diff --git a/patches/openvm-sdk/contracts/lib/.gitignore b/patches/openvm-sdk/contracts/lib/.gitignore deleted file mode 100644 index 03cabd3d..00000000 --- a/patches/openvm-sdk/contracts/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -forge-std/ diff --git a/patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol b/patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol deleted file mode 100644 index ac8292cd..00000000 --- a/patches/openvm-sdk/contracts/src/IOpenVmHalo2Verifier.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IOpenVmHalo2Verifier { - function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) - external - view; -} diff --git a/patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol b/patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol deleted file mode 100644 index 8f6f2b57..00000000 --- a/patches/openvm-sdk/contracts/template/OpenVmHalo2Verifier.sol +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.19; - -import { Halo2Verifier } from "./Halo2Verifier.sol"; -import { IOpenVmHalo2Verifier } from "./interfaces/IOpenVmHalo2Verifier.sol"; - -type MemoryPointer is uint256; - -/// @notice This contract provides a thin wrapper around the Halo2 verifier -/// outputted by `snark-verifier`, exposing a more user-friendly interface. -contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { - /// @dev Invalid public values length - error InvalidPublicValuesLength(uint256 expected, uint256 actual); - - /// @dev Invalid proof data length - error InvalidProofDataLength(uint256 expected, uint256 actual); - - /// @dev Proof verification failed - error ProofVerificationFailed(); - - /// @dev The length of the proof data, in bytes. - uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32; - - /// @dev The number of public value limbs exposed by the Halo2 circuit. - /// This value is set by OpenVM and is guaranteed to be no larger than 8192. - uint256 private constant PUBLIC_VALUES_LENGTH = {PUBLIC_VALUES_LENGTH}; - - /// @dev The byte width of each public value limb (1 for rv32, 2 for rv64). - uint256 private constant PUBLIC_VALUES_LIMB_SIZE = {PUBLIC_VALUES_LIMB_SIZE}; - - /// @dev The total byte length of the public values payload. - uint256 private constant PUBLIC_VALUES_BYTE_LENGTH = PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE; - - /// @dev The length of the full proof, in bytes - uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32; - - /// @dev The version of OpenVM that generated this verifier. - string public constant OPENVM_VERSION = "{OPENVM_VERSION}"; - - /// @notice A wrapper that constructs the proof into the right format for - /// use with the `snark-verifier` verification. - /// - /// @dev The verifier expected proof format is: - /// proof[..12 * 32]: KZG accumulator - /// proof[12 * 32..13 * 32]: app exe commit - /// proof[13 * 32..14 * 32]: app vm commit - /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] - /// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix - /// - /// @param publicValues The PVs revealed by the OpenVM guest program. Each - /// public-value limb occupies PUBLIC_VALUES_LIMB_SIZE bytes in little-endian. - /// @param proofData All components of the proof except the public values and - /// app exe and vm commits. The expected format is: - /// `abi.encodePacked(kzgAccumulator, proofSuffix)` - /// @param appExeCommit The commitment to the OpenVM application executable whose execution - /// is being verified. - /// @param appVmCommit The commitment to the VM configuration. - function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { - if (publicValues.length != PUBLIC_VALUES_BYTE_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_BYTE_LENGTH, publicValues.length); - if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length); - - // We will format the public values and construct the full proof payload - // below. - - MemoryPointer proofPtr = _constructProof(publicValues, proofData, appExeCommit, appVmCommit); - - uint256 fullProofLength = FULL_PROOF_LENGTH; - - /// @solidity memory-safe-assembly - assembly { - // Self-call using the proof as calldata - if iszero(staticcall(gas(), address(), proofPtr, fullProofLength, 0, 0)) { - mstore(0x00, 0xd611c318) // ProofVerificationFailed() - revert(0x1c, 0x04) - } - } - } - - /// @dev The assembly code should perform the same function as the following - /// solidity code: - // - /// ```solidity - /// bytes memory proof = - /// abi.encodePacked(proofData[0:0x180], appExeCommit, appVmCommit, publicValuesPayload, proofData[0x180:]); - /// ``` - // - /// where `publicValuesPayload` is a memory payload with each byte in - /// `publicValues` separated into its own `bytes32` word. - /// - /// This function does not clean the memory it allocates. Since it is the - /// only memory write that occurs in the call frame, we know that - /// the memory region cannot have been dirtied. - /// - /// @return proofPtr Memory pointer to the beginning of the constructed - /// proof. This pointer does not follow `bytes memory` semantics. - function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) - internal - pure - returns (MemoryPointer proofPtr) - { - uint256 fullProofLength = FULL_PROOF_LENGTH; - - // The expected proof format using hex offsets: - // - // proof[..0x180]: KZG accumulator - // proof[0x180..0x1a0]: app exe commit - // proof[0x1a0..0x1c0]: app vm commit - // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] - // proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix - - /// @solidity memory-safe-assembly - assembly { - proofPtr := mload(0x40) - // Allocate the memory as a safety measure. - mstore(0x40, add(proofPtr, fullProofLength)) - - // Copy the KZG accumulator (length 0x180) into the beginning of - // the memory buffer - calldatacopy(proofPtr, proofData.offset, 0x180) - - // Copy the App Exe Commit and App Vm Commit into the memory buffer - mstore(add(proofPtr, 0x180), appExeCommit) - mstore(add(proofPtr, 0x1a0), appVmCommit) - - // Copy the Proof Suffix (length 43 * 32 = 0x560) into the - // end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in - // between for the publicValuesPayload. - // - // Begin copying from the end of the KZG accumulator in the - // calldata buffer (0x180) - let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) - calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) - - // Copy each public-value limb into the low bytes of the corresponding - // Fr slot. user_public_values stores limbs in little-endian, but each - // 32-byte word is interpreted by the EVM as big-endian, so we reverse - // the limb bytes as we copy them to the end of the word. - for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - let wordPtr := add(proofPtr, add(0x1c0, shl(5, i))) - // Clear the full word first; only the low bytes are overwritten. - mstore(wordPtr, 0) - for { let j := 0 } iszero(eq(j, PUBLIC_VALUES_LIMB_SIZE)) { j := add(j, 1) } { - // publicValues[i*LIMB_SIZE + j] is copied to the j-th byte - // from the end of the word, i.e. wordPtr + (0x1f - j). - calldatacopy( - add(wordPtr, sub(0x1f, j)), - add(publicValues.offset, add(mul(i, PUBLIC_VALUES_LIMB_SIZE), j)), - 0x01 - ) - } - } - } - } -} diff --git a/patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol b/patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol deleted file mode 100644 index 2547ba18..00000000 --- a/patches/openvm-sdk/contracts/test/OpenVmHalo2Verifier.t.sol +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.19; - -import { LibString } from "./helpers/LibString.sol"; -import { Test, console2, safeconsole as console } from "forge-std/Test.sol"; -import { IOpenVmHalo2Verifier } from "../src/IOpenVmHalo2Verifier.sol"; - -contract TemplateTest is Test { - bytes proofData; - bytes32 appExeCommit = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - bytes32 appVmCommit = 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE; - bytes guestPvs; - - uint256 publicValuesLength; - uint256 fullProofWords; - uint256 fullProofLength; - - string _code = vm.readFile("template/OpenVmHalo2Verifier.sol"); - string deps = vm.readFile("test/helpers/MockDeps.sol"); - - function setUp() public { - proofData = new bytes(55 * 32); - for (uint256 i = 0; i < 55; i++) { - for (uint256 j = 0; j < 32; j++) { - proofData[i * 32 + j] = bytes1(uint8(i)); - } - } - } - - /// forge-config: default.fuzz.runs = 10 - function testFuzz_ProofFormat(uint256 _publicValuesLength) public { - publicValuesLength = bound(_publicValuesLength, 1, 10_000); - publicValuesLength = 8; - fullProofWords = (12 + 2 + publicValuesLength + 43); - fullProofLength = fullProofWords * 32; - - guestPvs = new bytes(publicValuesLength); - for (uint256 i = 0; i < publicValuesLength; i++) { - guestPvs[i] = bytes1(uint8(i)); - } - - IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); - - (bool success,) = address(verifier).delegatecall( - abi.encodeCall(IOpenVmHalo2Verifier.verify, (guestPvs, proofData, appExeCommit, appVmCommit)) - ); - require(success, "Verification failed"); - } - - fallback(bytes calldata proof) external returns (bytes memory) { - bytes memory proofDataExpected = proofData; - - uint256 proofSuffixOffset = 0x1c0 + (32 * publicValuesLength); - - bytes memory kzgAccumulator = proof[0:0x180]; - bytes memory proofSuffix = proof[proofSuffixOffset:]; - bytes memory _proofData = abi.encodePacked(kzgAccumulator, proofSuffix); - - require(keccak256(_proofData) == keccak256(proofDataExpected), "Partial proof mismatch"); - - bytes memory _appExeCommit = proof[0x180:0x1a0]; - bytes memory _appVmCommit = proof[0x1a0:0x1c0]; - - require(bytes32(_appExeCommit) == appExeCommit, "App exe commit mismatch"); - require(bytes32(_appVmCommit) == appVmCommit, "App vm commit mismatch"); - - bytes calldata _guestPvs = proof[0x1c0:0x1c0 + 32 * publicValuesLength]; - for (uint256 i = 0; i < publicValuesLength; ++i) { - uint256 expected = uint256(uint8(guestPvs[i])); - uint256 actual = uint256(bytes32(_guestPvs[i * 32:(i + 1) * 32])); - require(expected == actual, "Guest PVs hash mismatch"); - } - - // Suppress return value warning - assembly { - return(0x00, 0x00) - } - } - - function test_RevertWhen_InvalidPublicValuesLength() public { - publicValuesLength = 32; - IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); - - bytes memory invalidPvs = new bytes(0); - bytes4 sig = bytes4(keccak256("InvalidPublicValuesLength(uint256,uint256)")); - - vm.expectRevert(abi.encodeWithSelector(sig, 32, invalidPvs.length)); - verifier.verify(invalidPvs, hex"", bytes32(0), bytes32(0)); - } - - function test_RevertWhen_InvalidProofDataLength() public { - publicValuesLength = 32; - IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); - - bytes memory invalidProofData = new bytes(0); - bytes4 sig = bytes4(keccak256("InvalidProofDataLength(uint256,uint256)")); - - bytes memory pvs = new bytes(publicValuesLength); - - vm.expectRevert(abi.encodeWithSelector(sig, 55 * 32, invalidProofData.length)); - verifier.verify(pvs, invalidProofData, appExeCommit, appVmCommit); - } - - function test_RevertWhen_ProofVerificationFailed() public { - publicValuesLength = 32; - IOpenVmHalo2Verifier verifier = _compileAndDeployOpenVmVerifier(publicValuesLength); - - bytes memory _proofData = new bytes(55 * 32); - bytes memory pvs = new bytes(publicValuesLength); - - bytes4 sig = bytes4(keccak256("ProofVerificationFailed()")); - - vm.expectRevert(abi.encodeWithSelector(sig)); - verifier.verify(pvs, _proofData, appExeCommit, appVmCommit); - } - - function _compileAndDeployOpenVmVerifier(uint256 _publicValuesLength) - private - returns (IOpenVmHalo2Verifier verifier) - { - string memory code = LibString.replace(_code, "{PUBLIC_VALUES_LENGTH}", LibString.toString(_publicValuesLength)); - - // `code` will look like this: - // - // // SPDX-License-Identifier: MIT - // pragma solidity 0.8.19; - // - // import { Halo2Verifier } ... - // import { IOpenVmHalo2Verifier } ... - // - // contract OpenVmHalo2Verifier { .. } - // - // We want to replace the `import` statements with inlined deps for JIT - // compilation. - string memory inlinedCode = LibString.replace( - code, - "import { Halo2Verifier } from \"./Halo2Verifier.sol\";\nimport { IOpenVmHalo2Verifier } from \"./interfaces/IOpenVmHalo2Verifier.sol\";", - deps - ); - - // Must use solc 0.8.19 - string[] memory commands = new string[](3); - commands[0] = "sh"; - commands[1] = "-c"; - commands[2] = string.concat( - "echo ", - "'", - inlinedCode, - "'", - " | solc --no-optimize-yul --bin --optimize --optimize-runs 100000 - ", - " | awk 'BEGIN{found=0} /:OpenVmHalo2Verifier/ {found=1; next} found && /^Binary:/ {getline; print; exit}'" - ); - - bytes memory compiledVerifier = vm.ffi(commands); - - assembly { - verifier := create(0, add(compiledVerifier, 0x20), mload(compiledVerifier)) - if iszero(extcodesize(verifier)) { revert(0, 0) } - } - } -} diff --git a/patches/openvm-sdk/contracts/test/helpers/LibString.sol b/patches/openvm-sdk/contracts/test/helpers/LibString.sol deleted file mode 100644 index f046fa40..00000000 --- a/patches/openvm-sdk/contracts/test/helpers/LibString.sol +++ /dev/null @@ -1,1628 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -/// @notice Library for byte related operations. -/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol) -library LibBytes { - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* STRUCTS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Goated bytes storage struct that totally MOGs, no cap, fr. - /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af. - /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. - struct BytesStorage { - bytes32 _spacer; - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* CONSTANTS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev The constant returned when the `search` is not found in the bytes. - uint256 internal constant NOT_FOUND = type(uint256).max; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* BYTE STORAGE OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Sets the value of the bytes storage `$` to `s`. - function set(BytesStorage storage $, bytes memory s) internal { - /// @solidity memory-safe-assembly - assembly { - let n := mload(s) - let packed := or(0xff, shl(8, n)) - for { let i := 0 } 1 { } { - if iszero(gt(n, 0xfe)) { - i := 0x1f - packed := or(n, shl(8, mload(add(s, i)))) - if iszero(gt(n, i)) { break } - } - let o := add(s, 0x20) - mstore(0x00, $.slot) - for { let p := keccak256(0x00, 0x20) } 1 { } { - sstore(add(p, shr(5, i)), mload(add(o, i))) - i := add(i, 0x20) - if iszero(lt(i, n)) { break } - } - break - } - sstore($.slot, packed) - } - } - - /// @dev Sets the value of the bytes storage `$` to `s`. - function setCalldata(BytesStorage storage $, bytes calldata s) internal { - /// @solidity memory-safe-assembly - assembly { - let packed := or(0xff, shl(8, s.length)) - for { let i := 0 } 1 { } { - if iszero(gt(s.length, 0xfe)) { - i := 0x1f - packed := or(s.length, shl(8, shr(8, calldataload(s.offset)))) - if iszero(gt(s.length, i)) { break } - } - mstore(0x00, $.slot) - for { let p := keccak256(0x00, 0x20) } 1 { } { - sstore(add(p, shr(5, i)), calldataload(add(s.offset, i))) - i := add(i, 0x20) - if iszero(lt(i, s.length)) { break } - } - break - } - sstore($.slot, packed) - } - } - - /// @dev Sets the value of the bytes storage `$` to the empty bytes. - function clear(BytesStorage storage $) internal { - delete $._spacer; - } - - /// @dev Returns whether the value stored is `$` is the empty bytes "". - function isEmpty(BytesStorage storage $) internal view returns (bool) { - return uint256($._spacer) & 0xff == uint256(0); - } - - /// @dev Returns the length of the value stored in `$`. - function length(BytesStorage storage $) internal view returns (uint256 result) { - result = uint256($._spacer); - /// @solidity memory-safe-assembly - assembly { - let n := and(0xff, result) - result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n)))) - } - } - - /// @dev Returns the value stored in `$`. - function get(BytesStorage storage $) internal view returns (bytes memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - let o := add(result, 0x20) - let packed := sload($.slot) - let n := shr(8, packed) - for { let i := 0 } 1 { } { - if iszero(eq(or(packed, 0xff), packed)) { - mstore(o, packed) - n := and(0xff, packed) - i := 0x1f - if iszero(gt(n, i)) { break } - } - mstore(0x00, $.slot) - for { let p := keccak256(0x00, 0x20) } 1 { } { - mstore(add(o, i), sload(add(p, shr(5, i)))) - i := add(i, 0x20) - if iszero(lt(i, n)) { break } - } - break - } - mstore(result, n) // Store the length of the memory. - mstore(add(o, n), 0) // Zeroize the slot after the bytes. - mstore(0x40, add(add(o, n), 0x20)) // Allocate memory. - } - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* BYTES OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. - function replace(bytes memory subject, bytes memory needle, bytes memory replacement) - internal - pure - returns (bytes memory result) - { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - let needleLen := mload(needle) - let replacementLen := mload(replacement) - let d := sub(result, subject) // Memory difference. - let i := add(subject, 0x20) // Subject bytes pointer. - mstore(0x00, add(i, mload(subject))) // End of subject. - if iszero(gt(needleLen, mload(subject))) { - let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1) - let h := 0 // The hash of `needle`. - if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } - let s := mload(add(needle, 0x20)) - for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 { } { - let t := mload(i) - // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. - if iszero(shr(m, xor(t, s))) { - if h { - if iszero(eq(keccak256(i, needleLen), h)) { - mstore(add(i, d), t) - i := add(i, 1) - if iszero(lt(i, subjectSearchEnd)) { break } - continue - } - } - // Copy the `replacement` one word at a time. - for { let j := 0 } 1 { } { - mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) - j := add(j, 0x20) - if iszero(lt(j, replacementLen)) { break } - } - d := sub(add(d, replacementLen), needleLen) - if needleLen { - i := add(i, needleLen) - if iszero(lt(i, subjectSearchEnd)) { break } - continue - } - } - mstore(add(i, d), t) - i := add(i, 1) - if iszero(lt(i, subjectSearchEnd)) { break } - } - } - let end := mload(0x00) - let n := add(sub(d, add(result, 0x20)), end) - // Copy the rest of the bytes one word at a time. - for { } lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } - let o := add(i, d) - mstore(o, 0) // Zeroize the slot after the bytes. - mstore(0x40, add(o, 0x20)) // Allocate memory. - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from left to right, starting from `from`. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function indexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { - /// @solidity memory-safe-assembly - assembly { - result := not(0) // Initialize to `NOT_FOUND`. - for { let subjectLen := mload(subject) } 1 { } { - if iszero(mload(needle)) { - result := from - if iszero(gt(from, subjectLen)) { break } - result := subjectLen - break - } - let needleLen := mload(needle) - let subjectStart := add(subject, 0x20) - - subject := add(subjectStart, from) - let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) - let m := shl(3, sub(0x20, and(needleLen, 0x1f))) - let s := mload(add(needle, 0x20)) - - if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } - - if iszero(lt(needleLen, 0x20)) { - for { let h := keccak256(add(needle, 0x20), needleLen) } 1 { } { - if iszero(shr(m, xor(mload(subject), s))) { - if eq(keccak256(subject, needleLen), h) { - result := sub(subject, subjectStart) - break - } - } - subject := add(subject, 1) - if iszero(lt(subject, end)) { break } - } - break - } - for { } 1 { } { - if iszero(shr(m, xor(mload(subject), s))) { - result := sub(subject, subjectStart) - break - } - subject := add(subject, 1) - if iszero(lt(subject, end)) { break } - } - break - } - } - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from left to right. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { - return indexOf(subject, needle, 0); - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from right to left, starting from `from`. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from) - internal - pure - returns (uint256 result) - { - /// @solidity memory-safe-assembly - assembly { - for { } 1 { } { - result := not(0) // Initialize to `NOT_FOUND`. - let needleLen := mload(needle) - if gt(needleLen, mload(subject)) { break } - let w := result - - let fromMax := sub(mload(subject), needleLen) - if iszero(gt(fromMax, from)) { from := fromMax } - - let end := add(add(subject, 0x20), w) - subject := add(add(subject, 0x20), from) - if iszero(gt(subject, end)) { break } - // As this function is not too often used, - // we shall simply use keccak256 for smaller bytecode size. - for { let h := keccak256(add(needle, 0x20), needleLen) } 1 { } { - if eq(keccak256(subject, needleLen), h) { - result := sub(subject, add(end, 1)) - break - } - subject := add(subject, w) // `sub(subject, 1)`. - if iszero(gt(subject, end)) { break } - } - break - } - } - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from right to left. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function lastIndexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { - return lastIndexOf(subject, needle, type(uint256).max); - } - - /// @dev Returns true if `needle` is found in `subject`, false otherwise. - function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) { - return indexOf(subject, needle) != NOT_FOUND; - } - - /// @dev Returns whether `subject` starts with `needle`. - function startsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - let n := mload(needle) - // Just using keccak256 directly is actually cheaper. - let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n)) - result := lt(gt(n, mload(subject)), t) - } - } - - /// @dev Returns whether `subject` ends with `needle`. - function endsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - let n := mload(needle) - let notInRange := gt(n, mload(subject)) - // `subject + 0x20 + max(subject.length - needle.length, 0)`. - let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n))) - // Just using keccak256 directly is actually cheaper. - result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange) - } - } - - /// @dev Returns `subject` repeated `times`. - function repeat(bytes memory subject, uint256 times) internal pure returns (bytes memory result) { - /// @solidity memory-safe-assembly - assembly { - let l := mload(subject) // Subject length. - if iszero(or(iszero(times), iszero(l))) { - result := mload(0x40) - subject := add(subject, 0x20) - let o := add(result, 0x20) - for { } 1 { } { - // Copy the `subject` one word at a time. - for { let j := 0 } 1 { } { - mstore(add(o, j), mload(add(subject, j))) - j := add(j, 0x20) - if iszero(lt(j, l)) { break } - } - o := add(o, l) - times := sub(times, 1) - if iszero(times) { break } - } - mstore(o, 0) // Zeroize the slot after the bytes. - mstore(0x40, add(o, 0x20)) // Allocate memory. - mstore(result, sub(o, add(result, 0x20))) // Store the length. - } - } - } - - /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). - /// `start` and `end` are byte offsets. - function slice(bytes memory subject, uint256 start, uint256 end) internal pure returns (bytes memory result) { - /// @solidity memory-safe-assembly - assembly { - let l := mload(subject) // Subject length. - if iszero(gt(l, end)) { end := l } - if iszero(gt(l, start)) { start := l } - if lt(start, end) { - result := mload(0x40) - let n := sub(end, start) - let i := add(subject, start) - let w := not(0x1f) - // Copy the `subject` one word at a time, backwards. - for { let j := and(add(n, 0x1f), w) } 1 { } { - mstore(add(result, j), mload(add(i, j))) - j := add(j, w) // `sub(j, 0x20)`. - if iszero(j) { break } - } - let o := add(add(result, 0x20), n) - mstore(o, 0) // Zeroize the slot after the bytes. - mstore(0x40, add(o, 0x20)) // Allocate memory. - mstore(result, n) // Store the length. - } - } - } - - /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. - /// `start` is a byte offset. - function slice(bytes memory subject, uint256 start) internal pure returns (bytes memory result) { - result = slice(subject, start, type(uint256).max); - } - - /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). - /// `start` and `end` are byte offsets. Faster than Solidity's native slicing. - function sliceCalldata(bytes calldata subject, uint256 start, uint256 end) - internal - pure - returns (bytes calldata result) - { - /// @solidity memory-safe-assembly - assembly { - end := xor(end, mul(xor(end, subject.length), lt(subject.length, end))) - start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) - result.offset := add(subject.offset, start) - result.length := mul(lt(start, end), sub(end, start)) - } - } - - /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. - /// `start` is a byte offset. Faster than Solidity's native slicing. - function sliceCalldata(bytes calldata subject, uint256 start) internal pure returns (bytes calldata result) { - /// @solidity memory-safe-assembly - assembly { - start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) - result.offset := add(subject.offset, start) - result.length := mul(lt(start, subject.length), sub(subject.length, start)) - } - } - - /// @dev Reduces the size of `subject` to `n`. - /// If `n` is greater than the size of `subject`, this will be a no-op. - function truncate(bytes memory subject, uint256 n) internal pure returns (bytes memory result) { - /// @solidity memory-safe-assembly - assembly { - result := subject - mstore(mul(lt(n, mload(result)), result), n) - } - } - - /// @dev Returns a copy of `subject`, with the length reduced to `n`. - /// If `n` is greater than the size of `subject`, this will be a no-op. - function truncatedCalldata(bytes calldata subject, uint256 n) internal pure returns (bytes calldata result) { - /// @solidity memory-safe-assembly - assembly { - result.offset := subject.offset - result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n))) - } - } - - /// @dev Returns all the indices of `needle` in `subject`. - /// The indices are byte offsets. - function indicesOf(bytes memory subject, bytes memory needle) internal pure returns (uint256[] memory result) { - /// @solidity memory-safe-assembly - assembly { - let searchLen := mload(needle) - if iszero(gt(searchLen, mload(subject))) { - result := mload(0x40) - let i := add(subject, 0x20) - let o := add(result, 0x20) - let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) - let h := 0 // The hash of `needle`. - if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } - let s := mload(add(needle, 0x20)) - for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 { } { - let t := mload(i) - // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. - if iszero(shr(m, xor(t, s))) { - if h { - if iszero(eq(keccak256(i, searchLen), h)) { - i := add(i, 1) - if iszero(lt(i, subjectSearchEnd)) { break } - continue - } - } - mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. - o := add(o, 0x20) - i := add(i, searchLen) // Advance `i` by `searchLen`. - if searchLen { - if iszero(lt(i, subjectSearchEnd)) { break } - continue - } - } - i := add(i, 1) - if iszero(lt(i, subjectSearchEnd)) { break } - } - mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. - // Allocate memory for result. - // We allocate one more word, so this array can be recycled for {split}. - mstore(0x40, add(o, 0x20)) - } - } - } - - /// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes. - function split(bytes memory subject, bytes memory delimiter) internal pure returns (bytes[] memory result) { - uint256[] memory indices = indicesOf(subject, delimiter); - /// @solidity memory-safe-assembly - assembly { - let w := not(0x1f) - let indexPtr := add(indices, 0x20) - let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) - mstore(add(indicesEnd, w), mload(subject)) - mstore(indices, add(mload(indices), 1)) - for { let prevIndex := 0 } 1 { } { - let index := mload(indexPtr) - mstore(indexPtr, 0x60) - if iszero(eq(index, prevIndex)) { - let element := mload(0x40) - let l := sub(index, prevIndex) - mstore(element, l) // Store the length of the element. - // Copy the `subject` one word at a time, backwards. - for { let o := and(add(l, 0x1f), w) } 1 { } { - mstore(add(element, o), mload(add(add(subject, prevIndex), o))) - o := add(o, w) // `sub(o, 0x20)`. - if iszero(o) { break } - } - mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes. - // Allocate memory for the length and the bytes, rounded up to a multiple of 32. - mstore(0x40, add(element, and(add(l, 0x3f), w))) - mstore(indexPtr, element) // Store the `element` into the array. - } - prevIndex := add(index, mload(delimiter)) - indexPtr := add(indexPtr, 0x20) - if iszero(lt(indexPtr, indicesEnd)) { break } - } - result := indices - if iszero(mload(delimiter)) { - result := add(indices, 0x20) - mstore(result, sub(mload(indices), 2)) - } - } - } - - /// @dev Returns a concatenated bytes of `a` and `b`. - /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer. - function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - let w := not(0x1f) - let aLen := mload(a) - // Copy `a` one word at a time, backwards. - for { let o := and(add(aLen, 0x20), w) } 1 { } { - mstore(add(result, o), mload(add(a, o))) - o := add(o, w) // `sub(o, 0x20)`. - if iszero(o) { break } - } - let bLen := mload(b) - let output := add(result, aLen) - // Copy `b` one word at a time, backwards. - for { let o := and(add(bLen, 0x20), w) } 1 { } { - mstore(add(output, o), mload(add(b, o))) - o := add(o, w) // `sub(o, 0x20)`. - if iszero(o) { break } - } - let totalLen := add(aLen, bLen) - let last := add(add(result, 0x20), totalLen) - mstore(last, 0) // Zeroize the slot after the bytes. - mstore(result, totalLen) // Store the length. - mstore(0x40, add(last, 0x20)) // Allocate memory. - } - } - - /// @dev Returns whether `a` equals `b`. - function eq(bytes memory a, bytes memory b) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) - } - } - - /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes. - function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - // These should be evaluated on compile time, as far as possible. - let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. - let x := not(or(m, or(b, add(m, and(b, m))))) - let r := shl(7, iszero(iszero(shr(128, x)))) - r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) - r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) - r := or(r, shl(4, lt(0xffff, shr(r, x)))) - r := or(r, shl(3, lt(0xff, shr(r, x)))) - // forgefmt: disable-next-item - result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), - xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) - } - } - - /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. - /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. - function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) { - /// @solidity memory-safe-assembly - assembly { - let aLen := mload(a) - let bLen := mload(b) - let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f)) - if n { - for { let i := 0x20 } 1 { } { - let x := mload(add(a, i)) - let y := mload(add(b, i)) - if iszero(or(xor(x, y), eq(i, n))) { - i := add(i, 0x20) - continue - } - result := sub(gt(x, y), lt(x, y)) - break - } - } - // forgefmt: disable-next-item - if iszero(result) { - let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201 - let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0))) - let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0))) - result := sub(gt(x, y), lt(x, y)) - if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) } - } - } - } - - /// @dev Directly returns `a` without copying. - function directReturn(bytes memory a) internal pure { - /// @solidity memory-safe-assembly - assembly { - // Assumes that the bytes does not start from the scratch space. - let retStart := sub(a, 0x20) - let retUnpaddedSize := add(mload(a), 0x40) - // Right pad with zeroes. Just in case the bytes is produced - // by a method that doesn't zero right pad. - mstore(add(retStart, retUnpaddedSize), 0) - mstore(retStart, 0x20) // Store the return offset. - // End the transaction, returning the bytes. - return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) - } - } - - /// @dev Directly returns `a` with minimal copying. - function directReturn(bytes[] memory a) internal pure { - /// @solidity memory-safe-assembly - assembly { - let n := mload(a) // `a.length`. - let o := add(a, 0x20) // Start of elements in `a`. - let u := a // Highest memory slot. - let w := not(0x1f) - for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { - let c := add(o, shl(5, i)) // Location of pointer to `a[i]`. - let s := mload(c) // `a[i]`. - let l := mload(s) // `a[i].length`. - let r := and(l, 0x1f) // `a[i].length % 32`. - let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`. - // If `s` comes before `o`, or `s` is not zero right padded. - if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) { - let m := mload(0x40) - mstore(m, l) // Copy `a[i].length`. - for { } 1 { } { - mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards. - z := add(z, w) // `sub(z, 0x20)`. - if iszero(z) { break } - } - let e := add(add(m, 0x20), l) - mstore(e, 0) // Zeroize the slot after the copied bytes. - mstore(0x40, add(e, 0x20)) // Allocate memory. - s := m - } - mstore(c, sub(s, o)) // Convert to calldata offset. - let t := add(l, add(s, 0x20)) - if iszero(lt(t, u)) { u := t } - } - let retStart := add(a, w) // Assumes `a` doesn't start from scratch space. - mstore(retStart, 0x20) // Store the return offset. - return(retStart, add(0x40, sub(u, retStart))) // End the transaction. - } - } - - /// @dev Returns the word at `offset`, without any bounds checks. - function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(add(add(a, 0x20), offset)) - } - } - - /// @dev Returns the word at `offset`, without any bounds checks. - function loadCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes32 result) { - /// @solidity memory-safe-assembly - assembly { - result := calldataload(add(a.offset, offset)) - } - } - - /// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks. - function staticStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { - /// @solidity memory-safe-assembly - assembly { - let l := sub(a.length, 0x20) - result.offset := add(a.offset, offset) - result.length := sub(a.length, offset) - if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) } - } - } - - /// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks. - function dynamicStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { - /// @solidity memory-safe-assembly - assembly { - let l := sub(a.length, 0x20) - let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. - result.offset := add(a.offset, s) - result.length := sub(a.length, s) - if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) } - } - } - - /// @dev Returns bytes in calldata. Performs bounds checks. - function bytesInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { - /// @solidity memory-safe-assembly - assembly { - let l := sub(a.length, 0x20) - let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. - result.offset := add(add(a.offset, s), 0x20) - result.length := calldataload(add(a.offset, s)) - // forgefmt: disable-next-item - if or(shr(64, or(result.length, or(s, or(l, a.offset)))), - or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) } - } - } - - /// @dev Returns empty calldata bytes. For silencing the compiler. - function emptyCalldata() internal pure returns (bytes calldata result) { - /// @solidity memory-safe-assembly - assembly { - result.length := 0 - } - } -} - -/// @notice Library for converting numbers into strings and other string operations. -/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) -/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) -/// -/// @dev Note: -/// For performance and bytecode compactness, most of the string operations are restricted to -/// byte strings (7-bit ASCII), except where otherwise specified. -/// Usage of byte string operations on charsets with runes spanning two or more bytes -/// can lead to undefined behavior. -library LibString { - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* STRUCTS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Goated string storage struct that totally MOGs, no cap, fr. - /// Uses less gas and bytecode than Solidity's native string storage. It's meta af. - /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. - struct StringStorage { - bytes32 _spacer; - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* CUSTOM ERRORS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev The length of the output is too small to contain all the hex digits. - error HexLengthInsufficient(); - - /// @dev The length of the string is more than 32 bytes. - error TooBigForSmallString(); - - /// @dev The input string must be a 7-bit ASCII. - error StringNot7BitASCII(); - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* CONSTANTS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev The constant returned when the `search` is not found in the string. - uint256 internal constant NOT_FOUND = type(uint256).max; - - /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. - uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; - - /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. - uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; - - /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. - uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; - - /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. - uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; - - /// @dev Lookup for '0123456789'. - uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; - - /// @dev Lookup for '0123456789abcdefABCDEF'. - uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; - - /// @dev Lookup for '01234567'. - uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; - - /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. - uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; - - /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. - uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; - - /// @dev Lookup for ' \t\n\r\x0b\x0c'. - uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* STRING STORAGE OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Sets the value of the string storage `$` to `s`. - function set(StringStorage storage $, string memory s) internal { - LibBytes.set(bytesStorage($), bytes(s)); - } - - /// @dev Sets the value of the string storage `$` to `s`. - function setCalldata(StringStorage storage $, string calldata s) internal { - LibBytes.setCalldata(bytesStorage($), bytes(s)); - } - - /// @dev Sets the value of the string storage `$` to the empty string. - function clear(StringStorage storage $) internal { - delete $._spacer; - } - - /// @dev Returns whether the value stored is `$` is the empty string "". - function isEmpty(StringStorage storage $) internal view returns (bool) { - return uint256($._spacer) & 0xff == uint256(0); - } - - /// @dev Returns the length of the value stored in `$`. - function length(StringStorage storage $) internal view returns (uint256) { - return LibBytes.length(bytesStorage($)); - } - - /// @dev Returns the value stored in `$`. - function get(StringStorage storage $) internal view returns (string memory) { - return string(LibBytes.get(bytesStorage($))); - } - - /// @dev Helper to cast `$` to a `BytesStorage`. - function bytesStorage(StringStorage storage $) internal pure returns (LibBytes.BytesStorage storage casted) { - /// @solidity memory-safe-assembly - assembly { - casted.slot := $.slot - } - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* DECIMAL OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Returns the base 10 decimal representation of `value`. - function toString(uint256 value) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - // The maximum value of a uint256 contains 78 digits (1 byte per digit), but - // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. - // We will need 1 word for the trailing zeros padding, 1 word for the length, - // and 3 words for a maximum of 78 digits. - result := add(mload(0x40), 0x80) - mstore(0x40, add(result, 0x20)) // Allocate memory. - mstore(result, 0) // Zeroize the slot after the string. - - let end := result // Cache the end of the memory to calculate the length later. - let w := not(0) // Tsk. - // We write the string from rightmost digit to leftmost digit. - // The following is essentially a do-while loop that also handles the zero case. - for { let temp := value } 1 { } { - result := add(result, w) // `sub(result, 1)`. - // Store the character to the pointer. - // The ASCII index of the '0' character is 48. - mstore8(result, add(48, mod(temp, 10))) - temp := div(temp, 10) // Keep dividing `temp` until zero. - if iszero(temp) { break } - } - let n := sub(end, result) - result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length. - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the base 10 decimal representation of `value`. - function toString(int256 value) internal pure returns (string memory result) { - if (value >= 0) return toString(uint256(value)); - unchecked { - result = toString(~uint256(value) + 1); - } - /// @solidity memory-safe-assembly - assembly { - // We still have some spare memory space on the left, - // as we have allocated 3 words (96 bytes) for up to 78 digits. - let n := mload(result) // Load the string length. - mstore(result, 0x2d) // Store the '-' character. - result := sub(result, 1) // Move back the string pointer by a byte. - mstore(result, add(n, 1)) // Update the string length. - } - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* HEXADECIMAL OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Returns the hexadecimal representation of `value`, - /// left-padded to an input length of `byteCount` bytes. - /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, - /// giving a total length of `byteCount * 2 + 2` bytes. - /// Reverts if `byteCount` is too small for the output to contain all the digits. - function toHexString(uint256 value, uint256 byteCount) internal pure returns (string memory result) { - result = toHexStringNoPrefix(value, byteCount); - /// @solidity memory-safe-assembly - assembly { - let n := add(mload(result), 2) // Compute the length. - mstore(result, 0x3078) // Store the "0x" prefix. - result := sub(result, 2) // Move the pointer. - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the hexadecimal representation of `value`, - /// left-padded to an input length of `byteCount` bytes. - /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte, - /// giving a total length of `byteCount * 2` bytes. - /// Reverts if `byteCount` is too small for the output to contain all the digits. - function toHexStringNoPrefix(uint256 value, uint256 byteCount) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes - // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. - // We add 0x20 to the total and round down to a multiple of 0x20. - // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. - result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f))) - mstore(0x40, add(result, 0x20)) // Allocate memory. - mstore(result, 0) // Zeroize the slot after the string. - - let end := result // Cache the end to calculate the length later. - // Store "0123456789abcdef" in scratch space. - mstore(0x0f, 0x30313233343536373839616263646566) - - let start := sub(result, add(byteCount, byteCount)) - let w := not(1) // Tsk. - let temp := value - // We write the string from rightmost digit to leftmost digit. - // The following is essentially a do-while loop that also handles the zero case. - for { } 1 { } { - result := add(result, w) // `sub(result, 2)`. - mstore8(add(result, 1), mload(and(temp, 15))) - mstore8(result, mload(and(shr(4, temp), 15))) - temp := shr(8, temp) - if iszero(xor(result, start)) { break } - } - if temp { - mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. - revert(0x1c, 0x04) - } - let n := sub(end, result) - result := sub(result, 0x20) - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. - /// As address are 20 bytes long, the output will left-padded to have - /// a length of `20 * 2 + 2` bytes. - function toHexString(uint256 value) internal pure returns (string memory result) { - result = toHexStringNoPrefix(value); - /// @solidity memory-safe-assembly - assembly { - let n := add(mload(result), 2) // Compute the length. - mstore(result, 0x3078) // Store the "0x" prefix. - result := sub(result, 2) // Move the pointer. - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output is prefixed with "0x". - /// The output excludes leading "0" from the `toHexString` output. - /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. - function toMinimalHexString(uint256 value) internal pure returns (string memory result) { - result = toHexStringNoPrefix(value); - /// @solidity memory-safe-assembly - assembly { - let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. - let n := add(mload(result), 2) // Compute the length. - mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. - result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero. - mstore(result, sub(n, o)) // Store the length, accounting for leading zero. - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output excludes leading "0" from the `toHexStringNoPrefix` output. - /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. - function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { - result = toHexStringNoPrefix(value); - /// @solidity memory-safe-assembly - assembly { - let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. - let n := mload(result) // Get the length. - result := add(result, o) // Move the pointer, accounting for leading zero. - mstore(result, sub(n, o)) // Store the length, accounting for leading zero. - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output is encoded using 2 hexadecimal digits per byte. - /// As address are 20 bytes long, the output will left-padded to have - /// a length of `20 * 2` bytes. - function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, - // 0x02 bytes for the prefix, and 0x40 bytes for the digits. - // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. - result := add(mload(0x40), 0x80) - mstore(0x40, add(result, 0x20)) // Allocate memory. - mstore(result, 0) // Zeroize the slot after the string. - - let end := result // Cache the end to calculate the length later. - mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. - - let w := not(1) // Tsk. - // We write the string from rightmost digit to leftmost digit. - // The following is essentially a do-while loop that also handles the zero case. - for { let temp := value } 1 { } { - result := add(result, w) // `sub(result, 2)`. - mstore8(add(result, 1), mload(and(temp, 15))) - mstore8(result, mload(and(shr(4, temp), 15))) - temp := shr(8, temp) - if iszero(temp) { break } - } - let n := sub(end, result) - result := sub(result, 0x20) - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, - /// and the alphabets are capitalized conditionally according to - /// https://eips.ethereum.org/EIPS/eip-55 - function toHexStringChecksummed(address value) internal pure returns (string memory result) { - result = toHexString(value); - /// @solidity memory-safe-assembly - assembly { - let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` - let o := add(result, 0x22) - let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` - let t := shl(240, 136) // `0b10001000 << 240` - for { let i := 0 } 1 { } { - mstore(add(i, i), mul(t, byte(i, hashed))) - i := add(i, 1) - if eq(i, 20) { break } - } - mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) - o := add(o, 0x20) - mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. - function toHexString(address value) internal pure returns (string memory result) { - result = toHexStringNoPrefix(value); - /// @solidity memory-safe-assembly - assembly { - let n := add(mload(result), 2) // Compute the length. - mstore(result, 0x3078) // Store the "0x" prefix. - result := sub(result, 2) // Move the pointer. - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the hexadecimal representation of `value`. - /// The output is encoded using 2 hexadecimal digits per byte. - function toHexStringNoPrefix(address value) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - // Allocate memory. - // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, - // 0x02 bytes for the prefix, and 0x28 bytes for the digits. - // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. - mstore(0x40, add(result, 0x80)) - mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. - - result := add(result, 2) - mstore(result, 40) // Store the length. - let o := add(result, 0x20) - mstore(add(o, 40), 0) // Zeroize the slot after the string. - value := shl(96, value) - // We write the string from rightmost digit to leftmost digit. - // The following is essentially a do-while loop that also handles the zero case. - for { let i := 0 } 1 { } { - let p := add(o, add(i, i)) - let temp := byte(i, value) - mstore8(add(p, 1), mload(and(temp, 15))) - mstore8(p, mload(shr(4, temp))) - i := add(i, 1) - if eq(i, 20) { break } - } - } - } - - /// @dev Returns the hex encoded string from the raw bytes. - /// The output is encoded using 2 hexadecimal digits per byte. - function toHexString(bytes memory raw) internal pure returns (string memory result) { - result = toHexStringNoPrefix(raw); - /// @solidity memory-safe-assembly - assembly { - let n := add(mload(result), 2) // Compute the length. - mstore(result, 0x3078) // Store the "0x" prefix. - result := sub(result, 2) // Move the pointer. - mstore(result, n) // Store the length. - } - } - - /// @dev Returns the hex encoded string from the raw bytes. - /// The output is encoded using 2 hexadecimal digits per byte. - function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - let n := mload(raw) - result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. - mstore(result, add(n, n)) // Store the length of the output. - - mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. - let o := add(result, 0x20) - let end := add(raw, n) - for { } iszero(eq(raw, end)) { } { - raw := add(raw, 1) - mstore8(add(o, 1), mload(and(mload(raw), 15))) - mstore8(o, mload(and(shr(4, mload(raw)), 15))) - o := add(o, 2) - } - mstore(o, 0) // Zeroize the slot after the string. - mstore(0x40, add(o, 0x20)) // Allocate memory. - } - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* RUNE STRING OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Returns the number of UTF characters in the string. - function runeCount(string memory s) internal pure returns (uint256 result) { - /// @solidity memory-safe-assembly - assembly { - if mload(s) { - mstore(0x00, div(not(0), 255)) - mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) - let o := add(s, 0x20) - let end := add(o, mload(s)) - for { result := 1 } 1 { result := add(result, 1) } { - o := add(o, byte(0, mload(shr(250, mload(o))))) - if iszero(lt(o, end)) { break } - } - } - } - } - - /// @dev Returns if this string is a 7-bit ASCII string. - /// (i.e. all characters codes are in [0..127]) - function is7BitASCII(string memory s) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - result := 1 - let mask := shl(7, div(not(0), 255)) - let n := mload(s) - if n { - let o := add(s, 0x20) - let end := add(o, n) - let last := mload(end) - mstore(end, 0) - for { } 1 { } { - if and(mask, mload(o)) { - result := 0 - break - } - o := add(o, 0x20) - if iszero(lt(o, end)) { break } - } - mstore(end, last) - } - } - } - - /// @dev Returns if this string is a 7-bit ASCII string, - /// AND all characters are in the `allowed` lookup. - /// Note: If `s` is empty, returns true regardless of `allowed`. - function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - result := 1 - if mload(s) { - let allowed_ := shr(128, shl(128, allowed)) - let o := add(s, 0x20) - for { let end := add(o, mload(s)) } 1 { } { - result := and(result, shr(byte(0, mload(o)), allowed_)) - o := add(o, 1) - if iszero(and(result, lt(o, end))) { break } - } - } - } - } - - /// @dev Converts the bytes in the 7-bit ASCII string `s` to - /// an allowed lookup for use in `is7BitASCII(s, allowed)`. - /// To save runtime gas, you can cache the result in an immutable variable. - function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { - /// @solidity memory-safe-assembly - assembly { - if mload(s) { - let o := add(s, 0x20) - for { let end := add(o, mload(s)) } 1 { } { - result := or(result, shl(byte(0, mload(o)), 1)) - o := add(o, 1) - if iszero(lt(o, end)) { break } - } - if shr(128, result) { - mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. - revert(0x1c, 0x04) - } - } - } - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* BYTE STRING OPERATIONS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - // For performance and bytecode compactness, byte string operations are restricted - // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. - // Usage of byte string operations on charsets with runes spanning two or more bytes - // can lead to undefined behavior. - - /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. - function replace(string memory subject, string memory needle, string memory replacement) - internal - pure - returns (string memory) - { - return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement))); - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from left to right, starting from `from`. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function indexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { - return LibBytes.indexOf(bytes(subject), bytes(needle), from); - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from left to right. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function indexOf(string memory subject, string memory needle) internal pure returns (uint256) { - return LibBytes.indexOf(bytes(subject), bytes(needle), 0); - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from right to left, starting from `from`. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function lastIndexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { - return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from); - } - - /// @dev Returns the byte index of the first location of `needle` in `subject`, - /// needleing from right to left. - /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. - function lastIndexOf(string memory subject, string memory needle) internal pure returns (uint256) { - return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max); - } - - /// @dev Returns true if `needle` is found in `subject`, false otherwise. - function contains(string memory subject, string memory needle) internal pure returns (bool) { - return LibBytes.contains(bytes(subject), bytes(needle)); - } - - /// @dev Returns whether `subject` starts with `needle`. - function startsWith(string memory subject, string memory needle) internal pure returns (bool) { - return LibBytes.startsWith(bytes(subject), bytes(needle)); - } - - /// @dev Returns whether `subject` ends with `needle`. - function endsWith(string memory subject, string memory needle) internal pure returns (bool) { - return LibBytes.endsWith(bytes(subject), bytes(needle)); - } - - /// @dev Returns `subject` repeated `times`. - function repeat(string memory subject, uint256 times) internal pure returns (string memory) { - return string(LibBytes.repeat(bytes(subject), times)); - } - - /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). - /// `start` and `end` are byte offsets. - function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory) { - return string(LibBytes.slice(bytes(subject), start, end)); - } - - /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. - /// `start` is a byte offset. - function slice(string memory subject, uint256 start) internal pure returns (string memory) { - return string(LibBytes.slice(bytes(subject), start, type(uint256).max)); - } - - /// @dev Returns all the indices of `needle` in `subject`. - /// The indices are byte offsets. - function indicesOf(string memory subject, string memory needle) internal pure returns (uint256[] memory) { - return LibBytes.indicesOf(bytes(subject), bytes(needle)); - } - - /// @dev Returns an arrays of strings based on the `delimiter` inside of the `subject` string. - function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { - bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter)); - /// @solidity memory-safe-assembly - assembly { - result := a - } - } - - /// @dev Returns a concatenated string of `a` and `b`. - /// Cheaper than `string.concat()` and does not de-align the free memory pointer. - function concat(string memory a, string memory b) internal pure returns (string memory) { - return string(LibBytes.concat(bytes(a), bytes(b))); - } - - /// @dev Returns a copy of the string in either lowercase or UPPERCASE. - /// WARNING! This function is only compatible with 7-bit ASCII strings. - function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - let n := mload(subject) - if n { - result := mload(0x40) - let o := add(result, 0x20) - let d := sub(subject, result) - let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) - for { let end := add(o, n) } 1 { } { - let b := byte(0, mload(add(d, o))) - mstore8(o, xor(and(shr(b, flags), 0x20), b)) - o := add(o, 1) - if eq(o, end) { break } - } - mstore(result, n) // Store the length. - mstore(o, 0) // Zeroize the slot after the string. - mstore(0x40, add(o, 0x20)) // Allocate memory. - } - } - } - - /// @dev Returns a string from a small bytes32 string. - /// `s` must be null-terminated, or behavior will be undefined. - function fromSmallString(bytes32 s) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - let n := 0 - for { } byte(n, s) { n := add(n, 1) } { } // Scan for '\0'. - mstore(result, n) // Store the length. - let o := add(result, 0x20) - mstore(o, s) // Store the bytes of the string. - mstore(add(o, n), 0) // Zeroize the slot after the string. - mstore(0x40, add(result, 0x40)) // Allocate memory. - } - } - - /// @dev Returns the small string, with all bytes after the first null byte zeroized. - function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { - /// @solidity memory-safe-assembly - assembly { - for { } byte(result, s) { result := add(result, 1) } { } // Scan for '\0'. - mstore(0x00, s) - mstore(result, 0x00) - result := mload(0x00) - } - } - - /// @dev Returns the string as a normalized null-terminated small string. - function toSmallString(string memory s) internal pure returns (bytes32 result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(s) - if iszero(lt(result, 33)) { - mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. - revert(0x1c, 0x04) - } - result := shl(shl(3, sub(32, result)), mload(add(s, result))) - } - } - - /// @dev Returns a lowercased copy of the string. - /// WARNING! This function is only compatible with 7-bit ASCII strings. - function lower(string memory subject) internal pure returns (string memory result) { - result = toCase(subject, false); - } - - /// @dev Returns an UPPERCASED copy of the string. - /// WARNING! This function is only compatible with 7-bit ASCII strings. - function upper(string memory subject) internal pure returns (string memory result) { - result = toCase(subject, true); - } - - /// @dev Escapes the string to be used within HTML tags. - function escapeHTML(string memory s) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - let end := add(s, mload(s)) - let o := add(result, 0x20) - // Store the bytes of the packed offsets and strides into the scratch space. - // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. - mstore(0x1f, 0x900094) - mstore(0x08, 0xc0000000a6ab) - // Store ""&'<>" into the scratch space. - mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) - for { } iszero(eq(s, end)) { } { - s := add(s, 1) - let c := and(mload(s), 0xff) - // Not in `["\"","'","&","<",">"]`. - if iszero(and(shl(c, 1), 0x500000c400000000)) { - mstore8(o, c) - o := add(o, 1) - continue - } - let t := shr(248, mload(c)) - mstore(o, mload(and(t, 0x1f))) - o := add(o, shr(5, t)) - } - mstore(o, 0) // Zeroize the slot after the string. - mstore(result, sub(o, add(result, 0x20))) // Store the length. - mstore(0x40, add(o, 0x20)) // Allocate memory. - } - } - - /// @dev Escapes the string to be used within double-quotes in a JSON. - /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. - function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - let o := add(result, 0x20) - if addDoubleQuotes { - mstore8(o, 34) - o := add(1, o) - } - // Store "\\u0000" in scratch space. - // Store "0123456789abcdef" in scratch space. - // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. - // into the scratch space. - mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) - // Bitmask for detecting `["\"","\\"]`. - let e := or(shl(0x22, 1), shl(0x5c, 1)) - for { let end := add(s, mload(s)) } iszero(eq(s, end)) { } { - s := add(s, 1) - let c := and(mload(s), 0xff) - if iszero(lt(c, 0x20)) { - if iszero(and(shl(c, 1), e)) { - // Not in `["\"","\\"]`. - mstore8(o, c) - o := add(o, 1) - continue - } - mstore8(o, 0x5c) // "\\". - mstore8(add(o, 1), c) - o := add(o, 2) - continue - } - if iszero(and(shl(c, 1), 0x3700)) { - // Not in `["\b","\t","\n","\f","\d"]`. - mstore8(0x1d, mload(shr(4, c))) // Hex value. - mstore8(0x1e, mload(and(c, 15))) // Hex value. - mstore(o, mload(0x19)) // "\\u00XX". - o := add(o, 6) - continue - } - mstore8(o, 0x5c) // "\\". - mstore8(add(o, 1), mload(add(c, 8))) - o := add(o, 2) - } - if addDoubleQuotes { - mstore8(o, 34) - o := add(1, o) - } - mstore(o, 0) // Zeroize the slot after the string. - mstore(result, sub(o, add(result, 0x20))) // Store the length. - mstore(0x40, add(o, 0x20)) // Allocate memory. - } - } - - /// @dev Escapes the string to be used within double-quotes in a JSON. - function escapeJSON(string memory s) internal pure returns (string memory result) { - result = escapeJSON(s, false); - } - - /// @dev Encodes `s` so that it can be safely used in a URI, - /// just like `encodeURIComponent` in JavaScript. - /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent - /// See: https://datatracker.ietf.org/doc/html/rfc2396 - /// See: https://datatracker.ietf.org/doc/html/rfc3986 - function encodeURIComponent(string memory s) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - // Store "0123456789ABCDEF" in scratch space. - // Uppercased to be consistent with JavaScript's implementation. - mstore(0x0f, 0x30313233343536373839414243444546) - let o := add(result, 0x20) - for { let end := add(s, mload(s)) } iszero(eq(s, end)) { } { - s := add(s, 1) - let c := and(mload(s), 0xff) - // If not in `[0-9A-Z-a-z-_.!~*'()]`. - if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) { - mstore8(o, 0x25) // '%'. - mstore8(add(o, 1), mload(and(shr(4, c), 15))) - mstore8(add(o, 2), mload(and(c, 15))) - o := add(o, 3) - continue - } - mstore8(o, c) - o := add(o, 1) - } - mstore(result, sub(o, add(result, 0x20))) // Store the length. - mstore(o, 0) // Zeroize the slot after the string. - mstore(0x40, add(o, 0x20)) // Allocate memory. - } - } - - /// @dev Returns whether `a` equals `b`. - function eq(string memory a, string memory b) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) - } - } - - /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. - function eqs(string memory a, bytes32 b) internal pure returns (bool result) { - /// @solidity memory-safe-assembly - assembly { - // These should be evaluated on compile time, as far as possible. - let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. - let x := not(or(m, or(b, add(m, and(b, m))))) - let r := shl(7, iszero(iszero(shr(128, x)))) - r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) - r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) - r := or(r, shl(4, lt(0xffff, shr(r, x)))) - r := or(r, shl(3, lt(0xff, shr(r, x)))) - // forgefmt: disable-next-item - result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), - xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) - } - } - - /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. - /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. - function cmp(string memory a, string memory b) internal pure returns (int256) { - return LibBytes.cmp(bytes(a), bytes(b)); - } - - /// @dev Packs a single string with its length into a single word. - /// Returns `bytes32(0)` if the length is zero or greater than 31. - function packOne(string memory a) internal pure returns (bytes32 result) { - /// @solidity memory-safe-assembly - assembly { - // We don't need to zero right pad the string, - // since this is our own custom non-standard packing scheme. - result := - mul( - // Load the length and the bytes. - mload(add(a, 0x1f)), - // `length != 0 && length < 32`. Abuses underflow. - // Assumes that the length is valid and within the block gas limit. - lt(sub(mload(a), 1), 0x1f) - ) - } - } - - /// @dev Unpacks a string packed using {packOne}. - /// Returns the empty string if `packed` is `bytes32(0)`. - /// If `packed` is not an output of {packOne}, the output behavior is undefined. - function unpackOne(bytes32 packed) internal pure returns (string memory result) { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) // Grab the free memory pointer. - mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). - mstore(result, 0) // Zeroize the length slot. - mstore(add(result, 0x1f), packed) // Store the length and bytes. - mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. - } - } - - /// @dev Packs two strings with their lengths into a single word. - /// Returns `bytes32(0)` if combined length is zero or greater than 30. - function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { - /// @solidity memory-safe-assembly - assembly { - let aLen := mload(a) - // We don't need to zero right pad the strings, - // since this is our own custom non-standard packing scheme. - result := - mul( - or( // Load the length and the bytes of `a` and `b`. - shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))), - // `totalLen != 0 && totalLen < 31`. Abuses underflow. - // Assumes that the lengths are valid and within the block gas limit. - lt(sub(add(aLen, mload(b)), 1), 0x1e) - ) - } - } - - /// @dev Unpacks strings packed using {packTwo}. - /// Returns the empty strings if `packed` is `bytes32(0)`. - /// If `packed` is not an output of {packTwo}, the output behavior is undefined. - function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { - /// @solidity memory-safe-assembly - assembly { - resultA := mload(0x40) // Grab the free memory pointer. - resultB := add(resultA, 0x40) - // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. - mstore(0x40, add(resultB, 0x40)) - // Zeroize the length slots. - mstore(resultA, 0) - mstore(resultB, 0) - // Store the lengths and bytes. - mstore(add(resultA, 0x1f), packed) - mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) - // Right pad with zeroes. - mstore(add(add(resultA, 0x20), mload(resultA)), 0) - mstore(add(add(resultB, 0x20), mload(resultB)), 0) - } - } - - /// @dev Directly returns `a` without copying. - function directReturn(string memory a) internal pure { - /// @solidity memory-safe-assembly - assembly { - // Assumes that the string does not start from the scratch space. - let retStart := sub(a, 0x20) - let retUnpaddedSize := add(mload(a), 0x40) - // Right pad with zeroes. Just in case the string is produced - // by a method that doesn't zero right pad. - mstore(add(retStart, retUnpaddedSize), 0) - mstore(retStart, 0x20) // Store the return offset. - // End the transaction, returning the string. - return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) - } - } -} diff --git a/patches/openvm-sdk/contracts/test/helpers/MockDeps.sol b/patches/openvm-sdk/contracts/test/helpers/MockDeps.sol deleted file mode 100644 index 12296534..00000000 --- a/patches/openvm-sdk/contracts/test/helpers/MockDeps.sol +++ /dev/null @@ -1,12 +0,0 @@ -interface IOpenVmHalo2Verifier { - function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) - external - view; -} - -contract Halo2Verifier { - /// Mock verifier always reverts - fallback(bytes calldata) external returns (bytes memory) { - revert("Verification failed"); - } -} diff --git a/patches/openvm-sdk/examples/sdk_app.rs b/patches/openvm-sdk/examples/sdk_app.rs deleted file mode 100644 index e1ec30a8..00000000 --- a/patches/openvm-sdk/examples/sdk_app.rs +++ /dev/null @@ -1,45 +0,0 @@ -// [!region dependencies] -use openvm_build::GuestOptions; -use openvm_sdk::{config::AggregationSystemParams, prover::verify_app_proof, Sdk, StdIn}; -use openvm_stark_sdk::config::{app_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT}; -// [!endregion dependencies] - -#[allow(unused_variables, unused_doc_comments)] -fn main() -> eyre::Result<()> { - // [!region init] - // 1. Initialize the SDK with the standard configuration. - let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); - let agg_params = AggregationSystemParams::default(); - let sdk = Sdk::standard(app_params, agg_params); - // [!endregion init] - - // [!region build] - // 2 Build the ELF with default guest options and target filter. - let guest_opts = GuestOptions::default(); - let target_path = "your_path_project_root"; - let elf = sdk.build(guest_opts, target_path, &None, None)?; - // [!endregion build] - - let stdin = StdIn::default(); - - // [!region execution] - // 3. Run the program with default inputs. - let output = sdk.compile_and_execute(elf.clone(), stdin.clone())?; - println!("public values output: {output:?}"); - // [!endregion execution] - - // [!region proof_generation] - // 5. Generate an app proof. - let mut prover = sdk.app_prover(elf)?.with_program_name("test_program"); - let proof = prover.prove(stdin)?; - // [!endregion proof_generation] - - // [!region verification] - // 6. Do this once to save the app_vk, independent of the proof. - let (_app_pk, app_vk) = sdk.app_keygen(); - // 7. Verify your program. - let _ = verify_app_proof::(&app_vk, &proof)?; - // [!endregion verification] - - Ok(()) -} diff --git a/patches/openvm-sdk/examples/sdk_evm.rs b/patches/openvm-sdk/examples/sdk_evm.rs deleted file mode 100644 index 83527d62..00000000 --- a/patches/openvm-sdk/examples/sdk_evm.rs +++ /dev/null @@ -1,71 +0,0 @@ -// [!region dependencies] -use std::fs; - -use eyre::Result; -use openvm_build::GuestOptions; -use openvm_sdk::{config::AggregationSystemParams, Sdk, StdIn}; -use openvm_stark_sdk::config::{app_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -pub struct SomeStruct { - pub a: u64, - pub b: u64, -} -// [!endregion dependencies] - -#[allow(dead_code, unused_variables)] -fn read_elf() -> Result<(), Box> { - // [!region read_elf] - // 2b. Load the ELF from a file - let elf: Vec = fs::read("your_path_to_elf")?; - // [!endregion read_elf] - Ok(()) -} - -#[allow(unused_variables, unused_doc_comments)] -fn main() -> Result<(), Box> { - /// to import example guest code in crate replace `target_path` for: - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf(); - /// path.push("guest/fib"); - /// let target_path = path.to_str().unwrap(); - /// ``` - // [!region build] - // 1. Initialize the SDK with the RV64IM preset and default aggregation parameters. - let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); - let agg_params = AggregationSystemParams::default(); - let sdk = Sdk::riscv64(app_params, agg_params); - - // 2a. Build the ELF with guest options and a target filter. - let guest_opts = GuestOptions::default(); - let target_path = "your_path_project_root"; - let elf = sdk.build(guest_opts, target_path, &None, None)?; - // [!endregion build] - - // [!region input] - // 3. Format your input into StdIn - let my_input = SomeStruct { a: 1, b: 2 }; // anything that can be serialized - let mut stdin = StdIn::default(); - stdin.write(&my_input); - // [!endregion input] - - // [!region evm_verification] - // 5. Generate the SNARK verifier smart contract - let verifier = sdk.generate_halo2_verifier_solidity()?; - - // 6. Generate an EVM proof - // NOTE: if they have not been initialized already, this call will lazily generate the app, - // aggregation, root, and Halo2 proving keys before producing the final EVM proof. - let proof = sdk.prove_evm(elf, stdin, &[])?; - - // 7. Verify the EVM proof - // NOTE: you may compare the proof's executable and VM commits against an expected value by - // passing Some(app_commit) — e.g. `sdk.app_commit(elf)?` instead of None. - Sdk::verify_evm_halo2_proof(&verifier, proof, None)?; - // [!endregion evm_verification] - - Ok(()) -} diff --git a/patches/openvm-sdk/examples/sdk_stark.rs b/patches/openvm-sdk/examples/sdk_stark.rs deleted file mode 100644 index 175e2f50..00000000 --- a/patches/openvm-sdk/examples/sdk_stark.rs +++ /dev/null @@ -1,79 +0,0 @@ -// [!region dependencies] -use std::fs; - -use openvm_build::GuestOptions; -use openvm_sdk::{config::AggregationSystemParams, Sdk, StdIn}; -use openvm_stark_sdk::config::{app_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -pub struct SomeStruct { - pub a: u64, - pub b: u64, -} -// [!endregion dependencies] - -#[allow(dead_code, unused_variables)] -fn read_elf() -> eyre::Result<()> { - // [!region read_elf] - // 2b. Load the ELF from a file - let elf: Vec = fs::read("your_path_to_elf")?; - // [!endregion read_elf] - Ok(()) -} - -#[allow(unused_variables, unused_doc_comments)] -fn main() -> eyre::Result<()> { - /// to import example guest code in crate replace `target_path` for: - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf(); - /// path.push("guest/fib"); - /// let target_path = path.to_str().unwrap(); - /// ``` - // [!region build] - // 1. Initialize the SDK with the RV64IM preset and default aggregation parameters. - let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); - let agg_params = AggregationSystemParams::default(); - let sdk = Sdk::riscv64(app_params, agg_params); - - // 2a. Build the ELF with guest options and a target filter. - let guest_opts = GuestOptions::default(); - let target_path = "your_path_project_root"; - let elf = sdk.build(guest_opts, target_path, &None, None)?; - // [!endregion build] - - // [!region transpilation] - let exe = sdk.convert_to_exe(elf.clone())?; - // [!endregion transpilation] - - // [!region execution] - // 3. Format your input into StdIn - let my_input = SomeStruct { a: 1, b: 2 }; // anything that can be serialized - let mut stdin = StdIn::default(); - stdin.write(&my_input); - - // 4. Run the program - let output = sdk.compile_and_execute(exe.clone(), stdin.clone())?; - println!("public values output: {output:?}"); - // [!endregion execution] - - // [!region proof_generation] - // 5a. Generate a proof and verification baseline directly. - let (proof, baseline) = sdk.prove(exe.clone(), stdin.clone(), &[])?; - // 5b. Or build a StarkProver with custom fields and generate the baseline separately. - let mut prover = sdk.prover(exe)?.with_program_name("test_program"); - let baseline = prover.generate_baseline(); - let (proof, _metadata) = prover.prove(stdin.clone(), &[])?; - // [!endregion proof_generation] - - // [!region verification] - // 6. Do this once to save the aggregation VK, independent of the proof. - let (_agg_pk, agg_vk) = sdk.agg_keygen(); - // 7. Verify your program. - Sdk::verify_proof(agg_vk, baseline, &proof)?; - // [!endregion verification] - - Ok(()) -} diff --git a/patches/openvm-sdk/guest/fib/Cargo.toml b/patches/openvm-sdk/guest/fib/Cargo.toml deleted file mode 100644 index 5e8e1924..00000000 --- a/patches/openvm-sdk/guest/fib/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[workspace] -resolver = "2" - -[package] -name = "openvm-sdk-example-test" -version = "0.0.0" -edition = "2021" - -[dependencies] -openvm = { path = "../../../toolchain/openvm" } - -[features] -default = [] -std = ["openvm/std"] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } diff --git a/patches/openvm-sdk/guest/fib/openvm.toml b/patches/openvm-sdk/guest/fib/openvm.toml deleted file mode 100644 index 2c3d9e30..00000000 --- a/patches/openvm-sdk/guest/fib/openvm.toml +++ /dev/null @@ -1,3 +0,0 @@ -[app_vm_config.rv64i] -[app_vm_config.rv64m] -[app_vm_config.io] diff --git a/patches/openvm-sdk/guest/fib/src/main.rs b/patches/openvm-sdk/guest/fib/src/main.rs deleted file mode 100644 index d7da9a93..00000000 --- a/patches/openvm-sdk/guest/fib/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![cfg_attr( - all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), - no_main -)] -#![cfg_attr(not(feature = "std"), no_std)] - -openvm::entry!(main); - -fn fibonacci(n: u64) -> (u64, u64) { - if n <= 1 { - return (0, n); - } - let mut a: u64 = 0; - let mut b: u64 = 1; - for _ in 2..=n { - let sum = a + b; - a = b; - b = sum; - } - (a, b) -} - -pub fn main() { - // arbitrary n that results in more than 1 segment - let n = core::hint::black_box(1 << 5); - - let mut a = 0; - let mut b = 0; - // calculate nth fibonacci number n times - for _ in 0..n { - (a, b) = fibonacci(n); - } - - if a == 0 { - panic!(); - } - - openvm::io::reveal_u64(a, 0); - openvm::io::reveal_u64(b, 1); -} diff --git a/patches/openvm-sdk/guest/little/Cargo.toml b/patches/openvm-sdk/guest/little/Cargo.toml deleted file mode 100644 index 38b59551..00000000 --- a/patches/openvm-sdk/guest/little/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[workspace] -resolver = "2" - -[package] -name = "openvm-sdk-little-test" -version = "0.0.0" -edition = "2021" - -[dependencies] -openvm = { path = "../../../toolchain/openvm" } -openvm-algebra-guest = { path = "../../../../extensions/algebra/guest" } -openvm-ecc-guest = { path = "../../../../extensions/ecc/guest" } -openvm-pairing = { path = "../../../../guest-libs/pairing", features = [ - "bn254", - "bls12_381", -] } -openvm-k256 = { path = "../../../../guest-libs/k256", package = "k256" } -openvm-p256 = { path = "../../../../guest-libs/p256", package = "p256" } - -[features] -default = [] -std = ["openvm/std"] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } diff --git a/patches/openvm-sdk/guest/little/openvm.toml b/patches/openvm-sdk/guest/little/openvm.toml deleted file mode 100644 index 13094559..00000000 --- a/patches/openvm-sdk/guest/little/openvm.toml +++ /dev/null @@ -1,72 +0,0 @@ -[app_vm_config.rv64i] -[app_vm_config.rv64m] -[app_vm_config.io] - -[app_vm_config.keccak] -[app_vm_config.sha2] -[app_vm_config.bigint] - -[app_vm_config.modular] -supported_moduli = [ - # bn254 (alt bn128) - "21888242871839275222246405745257275088696311157297823662689037894645226208583", # coordinate field - "21888242871839275222246405745257275088548364400416034343698204186575808495617", # scalar field - # secp256k1 (k256) - "115792089237316195423570985008687907853269984665640564039457584007908834671663", # coordinate field - "115792089237316195423570985008687907852837564279074904382605163141518161494337", # scalar field - # secp256r1 (p256) - "115792089210356248762697446949407573530086143415290314195533631308867097853951", # coordinate - "115792089210356248762697446949407573529996955224135760342422259061068512044369", # scalar - # bls12_381 - "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", # coordinate field - "52435875175126190479447740508185965837690552500527637822603658699938581184513", # scalar field -] - -[app_vm_config.fp2] -supported_moduli = [ - [ - "Bn254Fp2", - # bn254 (alt bn128) - "21888242871839275222246405745257275088696311157297823662689037894645226208583", - ], - # Bls12_381 - [ - "Bls12_381Fp2", - "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", - ], -] - -# bn254 (alt bn128) -[[app_vm_config.ecc.supported_curves]] -struct_name = "Bn254G1Affine" -modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583" -scalar = "21888242871839275222246405745257275088548364400416034343698204186575808495617" -a = "0" -b = "3" - -# secp256k1 (k256) -[[app_vm_config.ecc.supported_curves]] -struct_name = "Secp256k1Point" -modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" -scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -a = "0" -b = "7" - -# secp256r1 (p256) -[[app_vm_config.ecc.supported_curves]] -struct_name = "P256Point" -modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" -scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" -a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" -b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" - -# bls12_381 -[[app_vm_config.ecc.supported_curves]] -struct_name = "Bls12_381G1Affine" -modulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787" -scalar = "52435875175126190479447740508185965837690552500527637822603658699938581184513" -a = "0" -b = "4" - -[app_vm_config.pairing] -supported_curves = ["Bn254", "Bls12_381"] diff --git a/patches/openvm-sdk/guest/little/openvm_init.rs b/patches/openvm-sdk/guest/little/openvm_init.rs deleted file mode 100644 index 257afb31..00000000 --- a/patches/openvm-sdk/guest/little/openvm_init.rs +++ /dev/null @@ -1,4 +0,0 @@ -// This file is automatically generated by cargo openvm. Do not rename or edit. -openvm_algebra_guest::moduli_macros::moduli_init! { "21888242871839275222246405745257275088696311157297823662689037894645226208583", "21888242871839275222246405745257275088548364400416034343698204186575808495617", "115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "115792089210356248762697446949407573530086143415290314195533631308867097853951", "115792089210356248762697446949407573529996955224135760342422259061068512044369", "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", "52435875175126190479447740508185965837690552500527637822603658699938581184513" } -openvm_algebra_guest::complex_macros::complex_init! { "Bn254Fp2" { mod_idx = 0 }, "Bls12_381Fp2" { mod_idx = 6 } } -openvm_ecc_guest::sw_macros::sw_init! { "Bn254G1Affine", "Secp256k1Point", "P256Point", "Bls12_381G1Affine" } diff --git a/patches/openvm-sdk/guest/little/src/main.rs b/patches/openvm-sdk/guest/little/src/main.rs deleted file mode 100644 index 2e72aea9..00000000 --- a/patches/openvm-sdk/guest/little/src/main.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![cfg_attr( - all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), - no_main -)] -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; - -use openvm_algebra_guest::IntMod; -use openvm_k256::{Secp256k1Coord, Secp256k1Scalar}; -use openvm_p256::{P256Coord, P256Scalar}; -use openvm_pairing::{bls12_381::Bls12_381Fp, bn254::Bn254Fp}; - -openvm::entry!(main); -openvm::init!(); - -// Based on https://en.wikipedia.org/wiki/Fermat%27s_little_theorem. If this -// fails, then F::MODULUS is not prime. -fn fermat() -where - F::Repr: AsRef<[u8]>, -{ - let mut pow = F::MODULUS; - pow.as_mut()[0] -= 2; - - let a = F::from_u32(1234); - let mut res = F::ONE; - let mut mut_a = a.clone(); - - for pow_byte in pow.as_ref() { - for j in 0..8 { - if pow_byte & (1 << j) != 0 { - res *= &mut_a; - } - mut_a *= mut_a.clone(); - } - } - - assert_eq!(res * a, F::ONE); -} - -pub fn main() { - fermat::(); - fermat::(); - fermat::(); - fermat::(); - fermat::(); - fermat::(); -} diff --git a/patches/openvm-sdk/guest/p256/Cargo.toml b/patches/openvm-sdk/guest/p256/Cargo.toml deleted file mode 100644 index 290469a7..00000000 --- a/patches/openvm-sdk/guest/p256/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[workspace] -resolver = "2" - -[package] -name = "openvm-sdk-p256-test" -version = "0.0.0" -edition = "2021" - -[dependencies] -openvm = { path = "../../../toolchain/openvm" } -openvm-algebra-guest = { path = "../../../../extensions/algebra/guest" } -openvm-ecc-guest = { path = "../../../../extensions/ecc/guest" } -openvm-pairing = { path = "../../../../guest-libs/pairing", features = [ - "bn254", - "bls12_381", -] } -openvm-k256 = { path = "../../../../guest-libs/k256", package = "k256" } -openvm-p256 = { path = "../../../../guest-libs/p256", package = "p256" } - -elliptic-curve = { version = "0.13.8" } - -[features] -default = [] -std = ["openvm/std"] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } - -[profile.release] -panic = "abort" -lto = "thin" diff --git a/patches/openvm-sdk/guest/p256/openvm.toml b/patches/openvm-sdk/guest/p256/openvm.toml deleted file mode 100644 index 13094559..00000000 --- a/patches/openvm-sdk/guest/p256/openvm.toml +++ /dev/null @@ -1,72 +0,0 @@ -[app_vm_config.rv64i] -[app_vm_config.rv64m] -[app_vm_config.io] - -[app_vm_config.keccak] -[app_vm_config.sha2] -[app_vm_config.bigint] - -[app_vm_config.modular] -supported_moduli = [ - # bn254 (alt bn128) - "21888242871839275222246405745257275088696311157297823662689037894645226208583", # coordinate field - "21888242871839275222246405745257275088548364400416034343698204186575808495617", # scalar field - # secp256k1 (k256) - "115792089237316195423570985008687907853269984665640564039457584007908834671663", # coordinate field - "115792089237316195423570985008687907852837564279074904382605163141518161494337", # scalar field - # secp256r1 (p256) - "115792089210356248762697446949407573530086143415290314195533631308867097853951", # coordinate - "115792089210356248762697446949407573529996955224135760342422259061068512044369", # scalar - # bls12_381 - "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", # coordinate field - "52435875175126190479447740508185965837690552500527637822603658699938581184513", # scalar field -] - -[app_vm_config.fp2] -supported_moduli = [ - [ - "Bn254Fp2", - # bn254 (alt bn128) - "21888242871839275222246405745257275088696311157297823662689037894645226208583", - ], - # Bls12_381 - [ - "Bls12_381Fp2", - "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", - ], -] - -# bn254 (alt bn128) -[[app_vm_config.ecc.supported_curves]] -struct_name = "Bn254G1Affine" -modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583" -scalar = "21888242871839275222246405745257275088548364400416034343698204186575808495617" -a = "0" -b = "3" - -# secp256k1 (k256) -[[app_vm_config.ecc.supported_curves]] -struct_name = "Secp256k1Point" -modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" -scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -a = "0" -b = "7" - -# secp256r1 (p256) -[[app_vm_config.ecc.supported_curves]] -struct_name = "P256Point" -modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" -scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" -a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" -b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" - -# bls12_381 -[[app_vm_config.ecc.supported_curves]] -struct_name = "Bls12_381G1Affine" -modulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787" -scalar = "52435875175126190479447740508185965837690552500527637822603658699938581184513" -a = "0" -b = "4" - -[app_vm_config.pairing] -supported_curves = ["Bn254", "Bls12_381"] diff --git a/patches/openvm-sdk/guest/p256/openvm_init.rs b/patches/openvm-sdk/guest/p256/openvm_init.rs deleted file mode 100644 index 257afb31..00000000 --- a/patches/openvm-sdk/guest/p256/openvm_init.rs +++ /dev/null @@ -1,4 +0,0 @@ -// This file is automatically generated by cargo openvm. Do not rename or edit. -openvm_algebra_guest::moduli_macros::moduli_init! { "21888242871839275222246405745257275088696311157297823662689037894645226208583", "21888242871839275222246405745257275088548364400416034343698204186575808495617", "115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "115792089210356248762697446949407573530086143415290314195533631308867097853951", "115792089210356248762697446949407573529996955224135760342422259061068512044369", "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", "52435875175126190479447740508185965837690552500527637822603658699938581184513" } -openvm_algebra_guest::complex_macros::complex_init! { "Bn254Fp2" { mod_idx = 0 }, "Bls12_381Fp2" { mod_idx = 6 } } -openvm_ecc_guest::sw_macros::sw_init! { "Bn254G1Affine", "Secp256k1Point", "P256Point", "Bls12_381G1Affine" } diff --git a/patches/openvm-sdk/guest/p256/src/main.rs b/patches/openvm-sdk/guest/p256/src/main.rs deleted file mode 100644 index 05ea9e75..00000000 --- a/patches/openvm-sdk/guest/p256/src/main.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![cfg_attr( - all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), - no_main -)] -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; - -use elliptic_curve::{ops::LinearCombination, CurveArithmetic, Field, Group, PrimeField}; -use openvm_p256::{NistP256, P256Point, P256Scalar as Scalar}; - -openvm::entry!(main); -openvm::init!(); - -pub fn main() { - let g = P256Point::generator(); - let a = P256Point::lincomb(&g, &Scalar::from_u128(100), &g, &Scalar::from_u128(156)); - let mut b = g; - for _ in 0..8 { - b += b; - } - assert_eq!(a, b); - - type NistScalar = ::Scalar; - - let a = NistScalar::from_u128(4); - let b = a.sqrt().unwrap(); - assert!(b == NistScalar::from_u128(2) || b == -NistScalar::from_u128(2)); - - let a = NistScalar::from_u128(5); - let b = a.sqrt().unwrap(); - let sqrt_5 = NistScalar::from_str_vartime( - "37706888570942939511621860890978929712654002332559277021296980149138421130241", - ) - .unwrap(); - assert!(b == sqrt_5 || b == -sqrt_5); - assert!(b * b == a); - - let a = NistScalar::from_u128(7); - let b = a.sqrt(); - assert!(bool::from(b.is_none())); -} diff --git a/patches/openvm-sdk/openvm_riscv64.toml b/patches/openvm-sdk/openvm_riscv64.toml deleted file mode 100644 index 2c3d9e30..00000000 --- a/patches/openvm-sdk/openvm_riscv64.toml +++ /dev/null @@ -1,3 +0,0 @@ -[app_vm_config.rv64i] -[app_vm_config.rv64m] -[app_vm_config.io] diff --git a/patches/openvm-sdk/openvm_standard.toml b/patches/openvm-sdk/openvm_standard.toml deleted file mode 100644 index 13094559..00000000 --- a/patches/openvm-sdk/openvm_standard.toml +++ /dev/null @@ -1,72 +0,0 @@ -[app_vm_config.rv64i] -[app_vm_config.rv64m] -[app_vm_config.io] - -[app_vm_config.keccak] -[app_vm_config.sha2] -[app_vm_config.bigint] - -[app_vm_config.modular] -supported_moduli = [ - # bn254 (alt bn128) - "21888242871839275222246405745257275088696311157297823662689037894645226208583", # coordinate field - "21888242871839275222246405745257275088548364400416034343698204186575808495617", # scalar field - # secp256k1 (k256) - "115792089237316195423570985008687907853269984665640564039457584007908834671663", # coordinate field - "115792089237316195423570985008687907852837564279074904382605163141518161494337", # scalar field - # secp256r1 (p256) - "115792089210356248762697446949407573530086143415290314195533631308867097853951", # coordinate - "115792089210356248762697446949407573529996955224135760342422259061068512044369", # scalar - # bls12_381 - "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", # coordinate field - "52435875175126190479447740508185965837690552500527637822603658699938581184513", # scalar field -] - -[app_vm_config.fp2] -supported_moduli = [ - [ - "Bn254Fp2", - # bn254 (alt bn128) - "21888242871839275222246405745257275088696311157297823662689037894645226208583", - ], - # Bls12_381 - [ - "Bls12_381Fp2", - "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", - ], -] - -# bn254 (alt bn128) -[[app_vm_config.ecc.supported_curves]] -struct_name = "Bn254G1Affine" -modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583" -scalar = "21888242871839275222246405745257275088548364400416034343698204186575808495617" -a = "0" -b = "3" - -# secp256k1 (k256) -[[app_vm_config.ecc.supported_curves]] -struct_name = "Secp256k1Point" -modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" -scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -a = "0" -b = "7" - -# secp256r1 (p256) -[[app_vm_config.ecc.supported_curves]] -struct_name = "P256Point" -modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" -scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" -a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" -b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" - -# bls12_381 -[[app_vm_config.ecc.supported_curves]] -struct_name = "Bls12_381G1Affine" -modulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787" -scalar = "52435875175126190479447740508185965837690552500527637822603658699938581184513" -a = "0" -b = "4" - -[app_vm_config.pairing] -supported_curves = ["Bn254", "Bls12_381"] diff --git a/patches/openvm-sdk/programs/Cargo.toml b/patches/openvm-sdk/programs/Cargo.toml deleted file mode 100644 index 7de70f13..00000000 --- a/patches/openvm-sdk/programs/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[workspace] -resolver = "2" - -[package] -name = "openvm-sdk-test-programs" -version = "0.0.0" -edition = "2021" - -[dependencies] -openvm = { path = "../../toolchain/openvm", default-features = false } -openvm-deferral-guest = { path = "../../../extensions/deferral/guest", default-features = false } -openvm-verify-stark-guest = { path = "../../../guest-libs/verify-stark/guest", default-features = false } - -[features] -default = [] -std = ["openvm/std"] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(openvm_intrinsics)', 'cfg(target_os, values("openvm"))'] } - -[profile.release] -panic = "abort" -lto = "thin" diff --git a/patches/openvm-sdk/programs/examples/fibonacci.elf b/patches/openvm-sdk/programs/examples/fibonacci.elf deleted file mode 100755 index 353f65bc1d5d535b92fa8bb24c9e9ffe45e956e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49008 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≫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 diff --git a/patches/openvm-sdk/programs/examples/verify-many.rs b/patches/openvm-sdk/programs/examples/verify-many.rs deleted file mode 100644 index 91c44f8d..00000000 --- a/patches/openvm-sdk/programs/examples/verify-many.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![cfg_attr( - all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), - no_main -)] -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; - -use alloc::vec::Vec; - -use openvm::io::read; -use openvm_deferral_guest::Commit; -use openvm_verify_stark_guest::{verify_stark, ProofOutput}; - -openvm::entry!(main); - -pub fn main() { - let app_exe_commit: Commit = read(); - let app_vm_commit: Commit = read(); - let user_public_values: Vec = read(); - - let expected = ProofOutput { - app_exe_commit, - app_vm_commit, - user_public_values, - }; - - let input_commit: Commit = read(); - verify_stark::<0>(&input_commit, &expected); - verify_stark::<1>(&input_commit, &expected); - verify_stark::<3>(&input_commit, &expected); - verify_stark::<4>(&input_commit, &expected); -} diff --git a/patches/openvm-sdk/programs/examples/verify-stark.elf b/patches/openvm-sdk/programs/examples/verify-stark.elf deleted file mode 100644 index b32d8b99d2fe5544f7aaf07337eec0e86c5842ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141928 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 fiPc{sv);t diff --git a/patches/openvm-sdk/programs/examples/verify-stark.rs b/patches/openvm-sdk/programs/examples/verify-stark.rs deleted file mode 100644 index 48436033..00000000 --- a/patches/openvm-sdk/programs/examples/verify-stark.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![cfg_attr( - all(not(feature = "std"), any(openvm_intrinsics, target_os = "openvm")), - no_main -)] -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; - -use alloc::vec::Vec; - -use openvm::io::read; -use openvm_deferral_guest::Commit; -use openvm_verify_stark_guest::{verify_stark, ProofOutput}; - -openvm::entry!(main); - -pub fn main() { - let app_exe_commit: Commit = read(); - let app_vm_commit: Commit = read(); - let user_public_values: Vec = read(); - - let expected = ProofOutput { - app_exe_commit, - app_vm_commit, - user_public_values, - }; - - let input_commit: Commit = read(); - verify_stark::<0>(&input_commit, &expected); -} diff --git a/patches/openvm-sdk/src/builder.rs b/patches/openvm-sdk/src/builder.rs deleted file mode 100644 index fd8d2a95..00000000 --- a/patches/openvm-sdk/src/builder.rs +++ /dev/null @@ -1,562 +0,0 @@ -use std::{ - marker::PhantomData, - sync::{Arc, OnceLock}, -}; - -use eyre::eyre; -use openvm_circuit::arch::{VmBuilder, VmExecutionConfig, VmExecutor}; -use openvm_sdk_config::TranspilerConfig; -use openvm_stark_backend::StarkEngine; -use openvm_transpiler::transpiler::Transpiler; -#[cfg(feature = "evm-prove")] -use { - crate::{ - config::Halo2Config, halo2_params::CacheHalo2ParamsReader, keygen::Halo2ProvingKey, - prover::Halo2Prover, - }, - openvm_static_verifier::StaticVerifierShape, - std::path::Path, -}; -#[cfg(feature = "root-prover")] -use { - crate::{keygen::RootProvingKey, prover::RootProver}, - openvm_stark_backend::SystemParams, - openvm_stark_sdk::config::root_params_with_100_bits_security, -}; - -use crate::{ - config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}, - keygen::{AggProvingKey, AppProvingKey}, - prover::{AggProver, DeferralPathProver, DeferralProver}, - GenericSdk, SdkError, F, SC, -}; - -enum AppSource { - Config(AppConfig), - Pk(AppProvingKey), -} - -#[allow(clippy::large_enum_variant)] -enum AggSource { - Params(AggregationSystemParams), - Pk(AggProvingKey), -} - -#[allow(clippy::large_enum_variant)] -enum DeferralSource { - Prover(DeferralProver), - PathProver(DeferralPathProver), -} - -#[cfg(feature = "root-prover")] -enum RootSource { - Params(SystemParams), - Pk(RootProvingKey), -} - -#[cfg(feature = "evm-prove")] -enum Halo2Source { - Config { - shape: StaticVerifierShape, - config: Halo2Config, - }, - Pk(Halo2ProvingKey), -} - -/// Construction-only API for [`GenericSdk`]. -/// -/// Each proving layer has one source of truth: either user-supplied config/params or a -/// pre-generated proving key. `build()` normalizes those sources into an immutable [`GenericSdk`]. -pub struct GenericSdkBuilder -where - E: StarkEngine, - VB: VmBuilder, - VB::VmConfig: VmExecutionConfig, -{ - app_source: Option>, - agg_source: Option, - #[cfg(feature = "root-prover")] - root_source: Option, - agg_tree_config: Option, - transpiler: Option>, - deferral_source: Option, - #[cfg(feature = "evm-prove")] - halo2_source: Option, - #[cfg(feature = "evm-prove")] - halo2_params_reader: Option, - _phantom: PhantomData, -} - -impl GenericSdkBuilder -where - E: StarkEngine, - VB: VmBuilder, - VB::VmConfig: VmExecutionConfig, -{ - /// Creates an empty builder with no configured proving layers. - pub fn new() -> Self { - Self::default() - } - - fn set_once(slot: &mut Option, field_name: &str, value: T) { - assert!(slot.is_none(), "{field_name} already set"); - *slot = Some(value); - } - - fn init_once_lock(value: Option, field_name: &str) -> OnceLock { - let lock = OnceLock::new(); - if let Some(value) = value { - assert!( - lock.set(value).is_ok(), - "{field_name} should only be initialized once" - ); - } - lock - } - - fn agg_config_from_pk(agg_pk: &AggProvingKey) -> AggregationConfig { - AggregationConfig { - params: AggregationSystemParams { - leaf: agg_pk.prefix.leaf.params.clone(), - internal: agg_pk.internal_recursive.params.clone(), - }, - } - } - - #[cfg(feature = "evm-prove")] - fn halo2_shape_from_pk(halo2_pk: &Halo2ProvingKey) -> StaticVerifierShape { - halo2_pk.verifier.shape - } - - #[cfg(feature = "evm-prove")] - fn halo2_config_from_pk(halo2_pk: &Halo2ProvingKey) -> Halo2Config { - Halo2Config { - wrapper_k: Some(halo2_pk.wrapper.pinning.metadata.config_params.k), - profiling: halo2_pk.profiling, - } - } - - fn build_deferral_path_prover( - agg_config: &AggregationConfig, - deferral_prover: DeferralProver, - ) -> Arc { - let agg_prover = AggProver::new( - deferral_prover.def_hook_prover.get_vk(), - agg_config.clone(), - AggregationTreeConfig::deferral(), - Some(deferral_prover.def_hook_prover.get_cached_commit()), - ); - Arc::new(DeferralPathProver { - deferral_prover: Arc::new(deferral_prover), - agg_prover: Arc::new(agg_prover), - }) - } - - fn require_dependency( - has_value: bool, - value_name: &str, - has_dependency: bool, - dependency_name: &str, - ) -> Result<(), SdkError> { - if has_value && !has_dependency { - return Err(SdkError::Other(eyre!( - "`{value_name}` requires `{dependency_name}` to also be set" - ))); - } - Ok(()) - } - - fn normalize_app_source( - app_source: AppSource, - ) -> (AppConfig, Option>) { - match app_source { - AppSource::Config(app_config) => (app_config, None), - AppSource::Pk(app_pk) => { - let app_config = app_pk.app_config(); - (app_config, Some(app_pk)) - } - } - } - - fn normalize_agg_source(agg_source: AggSource) -> (AggregationConfig, Option) { - match agg_source { - AggSource::Params(agg_params) => (AggregationConfig { params: agg_params }, None), - AggSource::Pk(agg_pk) => { - let agg_config = Self::agg_config_from_pk(&agg_pk); - (agg_config, Some(agg_pk)) - } - } - } - - #[cfg(feature = "root-prover")] - fn normalize_root_source(root_source: RootSource) -> (SystemParams, Option) { - match root_source { - RootSource::Params(root_params) => (root_params, None), - RootSource::Pk(root_pk) => (root_pk.root_pk.params.clone(), Some(root_pk)), - } - } - - #[cfg(feature = "evm-prove")] - fn normalize_halo2_source( - halo2_source: Halo2Source, - ) -> (StaticVerifierShape, Halo2Config, Option) { - match halo2_source { - Halo2Source::Config { shape, config } => (shape, config, None), - Halo2Source::Pk(halo2_pk) => ( - Self::halo2_shape_from_pk(&halo2_pk), - Self::halo2_config_from_pk(&halo2_pk), - Some(halo2_pk), - ), - } - } - - /// Uses the provided app configuration as the source of truth for app key generation. - pub fn app_config(mut self, app_config: AppConfig) -> Self { - Self::set_once( - &mut self.app_source, - "app_source", - AppSource::Config(app_config), - ); - self - } - - /// Seeds the SDK with a pre-generated app proving key and derives the app config from it. - pub fn app_pk(mut self, app_pk: AppProvingKey) -> Self { - Self::set_once(&mut self.app_source, "app_source", AppSource::Pk(app_pk)); - self - } - - /// Uses the provided aggregation parameters to generate aggregation proving material lazily. - pub fn agg_params(mut self, agg_params: AggregationSystemParams) -> Self { - Self::set_once( - &mut self.agg_source, - "agg_source", - AggSource::Params(agg_params), - ); - self - } - - /// Seeds the SDK with a pre-generated aggregation proving key. - pub fn agg_pk(mut self, agg_pk: AggProvingKey) -> Self { - Self::set_once(&mut self.agg_source, "agg_source", AggSource::Pk(agg_pk)); - self - } - - #[cfg(feature = "root-prover")] - /// Uses the provided root prover parameters to generate the root proving key lazily. - pub fn root_params(mut self, root_params: SystemParams) -> Self { - Self::set_once( - &mut self.root_source, - "root_source", - RootSource::Params(root_params), - ); - self - } - - #[cfg(feature = "root-prover")] - /// Seeds the SDK with a pre-generated root proving key. - pub fn root_pk(mut self, root_pk: RootProvingKey) -> Self { - Self::set_once( - &mut self.root_source, - "root_source", - RootSource::Pk(root_pk), - ); - self - } - - /// Overrides the aggregation tree fanout used when constructing aggregation provers. - pub fn agg_tree_config(mut self, agg_tree_config: AggregationTreeConfig) -> Self { - Self::set_once( - &mut self.agg_tree_config, - "agg_tree_config", - agg_tree_config, - ); - self - } - - /// Sets the transpiler used to convert guest ELFs into - /// [`VmExe`](openvm_circuit::arch::instructions::exe::VmExe)s. - pub fn transpiler(mut self, transpiler: Transpiler) -> Self { - Self::set_once(&mut self.transpiler, "transpiler", transpiler); - self - } - - /// Builds the SDK without inferring a transpiler from the app source. - /// - /// This is useful when callers only operate on pre-transpiled - /// [`VmExe`](openvm_circuit::arch::instructions::exe::VmExe) values and want ELF conversion - /// to remain unavailable unless a transpiler was explicitly supplied via - /// [`Self::transpiler`]. - pub fn build_without_transpiler(self) -> Result, SdkError> - where - VB: Default, - { - let app_source = self - .app_source - .ok_or_else(|| SdkError::Other(eyre!("`app_config` or `app_pk` must be set")))?; - let agg_source = self - .agg_source - .ok_or_else(|| SdkError::Other(eyre!("`agg_params` or `agg_pk` must be set")))?; - #[cfg(feature = "root-prover")] - let root_source = self - .root_source - .unwrap_or_else(|| RootSource::Params(root_params_with_100_bits_security())); - #[cfg(feature = "evm-prove")] - let halo2_source = self.halo2_source.unwrap_or(Halo2Source::Config { - shape: StaticVerifierShape::default(), - config: Halo2Config { - wrapper_k: None, - profiling: false, - }, - }); - - #[cfg(feature = "evm-prove")] - Self::require_dependency( - matches!(halo2_source, Halo2Source::Pk(_)), - "halo2_pk", - matches!(root_source, RootSource::Pk(_)), - "root_pk", - )?; - #[cfg(feature = "root-prover")] - Self::require_dependency( - matches!(root_source, RootSource::Pk(_)), - "root_pk", - matches!(agg_source, AggSource::Pk(_)), - "agg_pk", - )?; - Self::require_dependency( - matches!(agg_source, AggSource::Pk(_)), - "agg_pk", - matches!(app_source, AppSource::Pk(_)), - "app_pk", - )?; - - let Self { - app_source: _, - agg_source: _, - #[cfg(feature = "root-prover")] - root_source: _, - agg_tree_config, - transpiler, - deferral_source, - #[cfg(feature = "evm-prove")] - halo2_source: _, - #[cfg(feature = "evm-prove")] - halo2_params_reader, - _phantom: _, - } = self; - - let (app_config, app_pk_seed) = Self::normalize_app_source(app_source); - let (agg_config, agg_pk_seed) = Self::normalize_agg_source(agg_source); - #[cfg(feature = "root-prover")] - let (root_params, root_pk_seed) = Self::normalize_root_source(root_source); - - let executor = VmExecutor::new(app_config.app_vm_config.clone()) - .map_err(|e| SdkError::Vm(e.into()))?; - let agg_tree_config = agg_tree_config.unwrap_or_default(); - - let def_path_prover = match deferral_source { - Some(DeferralSource::Prover(deferral_prover)) => Some( - Self::build_deferral_path_prover(&agg_config, deferral_prover), - ), - Some(DeferralSource::PathProver(deferral_path_prover)) => { - Some(Arc::new(deferral_path_prover)) - } - None => None, - }; - let def_hook_cached_commit = def_path_prover - .as_ref() - .map(|def_path_prover| def_path_prover.def_hook_cached_commit()); - #[cfg(feature = "root-prover")] - let def_hook_commit = def_path_prover - .as_ref() - .map(|def_path_prover| def_path_prover.def_hook_commit()); - - let app_vm_vk = app_pk_seed - .as_ref() - .map(|app_pk| Arc::new(app_pk.app_vm_pk.vm_pk.get_vk())); - let app_pk = Self::init_once_lock(app_pk_seed, "app_pk"); - - let agg_prover_seed = agg_pk_seed.map(|agg_pk| { - let app_vm_vk = app_vm_vk.expect("validated `agg_pk` dependency on `app_pk`"); - Arc::new(AggProver::from_pk( - app_vm_vk, - agg_pk, - agg_tree_config, - def_hook_cached_commit, - )) - }); - - #[cfg(feature = "root-prover")] - let root_prover_seed = root_pk_seed.map(|root_pk| { - let agg_prover = agg_prover_seed - .as_ref() - .expect("validated `root_pk` dependency on `agg_pk`"); - let system_config = app_config.app_vm_config.as_ref(); - let memory_dimensions = system_config.memory_config.memory_dimensions(); - let num_user_pvs = system_config.num_public_values; - let internal_recursive_vk_commit = agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap() - .commitment - .into(); - - Arc::new(RootProver::from_pk( - agg_prover.internal_recursive_prover.get_vk(), - internal_recursive_vk_commit, - root_pk.root_pk, - memory_dimensions, - num_user_pvs, - def_hook_commit, - Some(root_pk.trace_heights), - )) - }); - - #[cfg(feature = "evm-prove")] - let halo2_params_reader = - halo2_params_reader.unwrap_or_else(CacheHalo2ParamsReader::new_with_default_params_dir); - #[cfg(feature = "evm-prove")] - let (halo2_shape, halo2_config, halo2_pk_seed) = Self::normalize_halo2_source(halo2_source); - #[cfg(feature = "evm-prove")] - let halo2_prover_seed = - halo2_pk_seed.map(|halo2_pk| Halo2Prover::new(&halo2_params_reader, halo2_pk)); - - Ok(GenericSdk { - app_config, - agg_config, - agg_tree_config, - #[cfg(feature = "root-prover")] - root_params, - #[cfg(feature = "evm-prove")] - halo2_shape, - #[cfg(feature = "evm-prove")] - halo2_config, - app_vm_builder: Default::default(), - transpiler, - executor, - app_pk, - agg_prover: Self::init_once_lock(agg_prover_seed, "agg_prover"), - #[cfg(feature = "root-prover")] - root_prover: Self::init_once_lock(root_prover_seed, "root_prover"), - def_path_prover, - #[cfg(feature = "evm-prove")] - halo2_params_reader, - #[cfg(feature = "evm-prove")] - halo2_prover: Self::init_once_lock(halo2_prover_seed, "halo2_prover"), - _phantom: PhantomData, - }) - } - - /// Builds the SDK, deriving a default transpiler from the app source when one was not - /// explicitly supplied via [`Self::transpiler`]. - pub fn build(mut self) -> Result, SdkError> - where - VB: Default, - VB::VmConfig: TranspilerConfig, - { - if self.transpiler.is_none() { - self.transpiler = self.app_source.as_ref().map(|app_source| match app_source { - AppSource::Config(app_config) => app_config.app_vm_config.transpiler(), - AppSource::Pk(app_pk) => app_pk.app_vm_pk.vm_config.transpiler(), - }); - } - self.build_without_transpiler() - } - - /// Enables deferrals in this SDK build. The [`DeferralProver`] must be created ahead of time - /// because the [`openvm_deferral_circuit::DeferralExtension`] should be created using - /// [`DeferralProver::make_extension`], which generates the `def_circuit_commits` needed by the - /// VM config. - pub fn deferral_prover(mut self, deferral_prover: DeferralProver) -> Self { - Self::set_once( - &mut self.deferral_source, - "deferral_source", - DeferralSource::Prover(deferral_prover), - ); - self - } - - /// Enables deferrals in this SDK build using a pre-built [`DeferralPathProver`]. - /// - /// This is mutually exclusive with [`Self::deferral_prover`]. Use this when the deferral - /// aggregation path has already been constructed, for example by - /// [`DeferralPathProver::verify_stark`]. - pub fn deferral_path_prover(mut self, deferral_path_prover: DeferralPathProver) -> Self { - Self::set_once( - &mut self.deferral_source, - "deferral_source", - DeferralSource::PathProver(deferral_path_prover), - ); - self - } - - #[cfg(feature = "evm-prove")] - /// Uses the provided Halo2 verifier shape and config to generate Halo2 proving material lazily. - pub fn halo2_config(mut self, shape: StaticVerifierShape, config: Halo2Config) -> Self { - Self::set_once( - &mut self.halo2_source, - "halo2_source", - Halo2Source::Config { shape, config }, - ); - self - } - - #[cfg(feature = "evm-prove")] - /// Seeds the SDK with a pre-generated Halo2 proving key. - pub fn halo2_pk(mut self, halo2_pk: Halo2ProvingKey) -> Self { - Self::set_once( - &mut self.halo2_source, - "halo2_source", - Halo2Source::Pk(halo2_pk), - ); - self - } - - #[cfg(feature = "evm-prove")] - /// Overrides the directory used to read or cache Halo2 parameters. - pub fn halo2_params_dir(mut self, params_dir: impl AsRef) -> Self { - Self::set_once( - &mut self.halo2_params_reader, - "halo2_params_reader", - CacheHalo2ParamsReader::new(params_dir), - ); - self - } -} - -impl Default for GenericSdkBuilder -where - E: StarkEngine, - VB: VmBuilder, - VB::VmConfig: VmExecutionConfig, -{ - fn default() -> Self { - Self { - app_source: None, - agg_source: None, - #[cfg(feature = "root-prover")] - root_source: None, - agg_tree_config: None, - transpiler: None, - deferral_source: None, - #[cfg(feature = "evm-prove")] - halo2_source: None, - #[cfg(feature = "evm-prove")] - halo2_params_reader: None, - _phantom: PhantomData, - } - } -} - -impl GenericSdk -where - E: StarkEngine, - VB: VmBuilder, - VB::VmConfig: VmExecutionConfig, -{ - /// Returns a builder for constructing an immutable [`GenericSdk`]. - pub fn builder() -> GenericSdkBuilder { - GenericSdkBuilder::new() - } -} diff --git a/patches/openvm-sdk/src/compiled.rs b/patches/openvm-sdk/src/compiled.rs deleted file mode 100644 index 80f09c2c..00000000 --- a/patches/openvm-sdk/src/compiled.rs +++ /dev/null @@ -1,66 +0,0 @@ -use openvm_circuit::arch::execution_mode::{MeteredCostCtx, MeteredCtx}; -#[cfg(not(feature = "rvr"))] -use openvm_circuit::arch::{execution_mode::ExecutionCtx, InterpretedInstance}; - -use crate::F; - -cfg_if::cfg_if! { - if #[cfg(feature = "rvr")] { - use openvm_circuit::arch::rvr::{ - RvrMeteredCostInstance, RvrMeteredInstance, RvrPureInstance, - }; - pub type CompiledExePure<'a, F> = RvrPureInstance<'a, F>; - pub type MeteredInstance<'a, F> = RvrMeteredInstance<'a, F>; - pub type MeteredCostInstance<'a, F> = RvrMeteredCostInstance<'a, F>; - } else if #[cfg(feature = "aot")] { - use openvm_circuit::arch::AotInstance; - pub type CompiledExePure<'a, F> = AotInstance<'a, F, ExecutionCtx>; - pub type MeteredInstance<'a, F> = AotInstance<'a, F, MeteredCtx>; - // AOT has no dedicated metered-cost backend; fall back to the interpreter. - pub type MeteredCostInstance<'a, F> = InterpretedInstance<'a, F, MeteredCostCtx>; - } else { - pub type CompiledExePure<'a, F> = InterpretedInstance<'a, F, ExecutionCtx>; - pub type MeteredInstance<'a, F> = InterpretedInstance<'a, F, MeteredCtx>; - pub type MeteredCostInstance<'a, F> = InterpretedInstance<'a, F, MeteredCostCtx>; - } -} - -/// Bundles a [`MeteredInstance`] with a precomputed [`MeteredCtx`] so each execution -/// just clones the ctx instead of rebuilding from the proving key. -pub struct CompiledExeMetered<'a> { - pub instance: MeteredInstance<'a, F>, - pub ctx: MeteredCtx, -} - -pub struct CompiledExeMeteredCost<'a> { - pub instance: MeteredCostInstance<'a, F>, - pub ctx: MeteredCostCtx, -} - -#[cfg(feature = "rvr")] -impl CompiledExeMetered<'_> { - /// Persist the compiled shared library into `dir`. Returns the path of - /// the copied `.so`/`.dylib`. The `MeteredCtx` is not persisted — it is - /// rebuilt from the proving key on load via - /// [`Sdk::load_compiled_metered`](crate::Sdk::load_compiled_metered). - pub fn save( - &self, - dir: &std::path::Path, - ) -> Result { - self.instance.save(dir) - } -} - -#[cfg(feature = "rvr")] -impl CompiledExeMeteredCost<'_> { - /// Persist the compiled shared library into `dir`. Returns the path of - /// the copied `.so`/`.dylib`. The `MeteredCostCtx` is not persisted — it - /// is rebuilt on load via - /// [`Sdk::load_compiled_metered_cost`](crate::Sdk::load_compiled_metered_cost). - pub fn save( - &self, - dir: &std::path::Path, - ) -> Result { - self.instance.save(dir) - } -} diff --git a/patches/openvm-sdk/src/config.rs b/patches/openvm-sdk/src/config.rs deleted file mode 100644 index 2d05fe3a..00000000 --- a/patches/openvm-sdk/src/config.rs +++ /dev/null @@ -1,112 +0,0 @@ -use clap::Args; -use openvm_sdk_config::SdkVmConfig; -use openvm_stark_backend::SystemParams; -use openvm_stark_sdk::config::{ - app_params_with_100_bits_security, internal_params_with_100_bits_security, - leaf_params_with_100_bits_security, MAX_APP_LOG_STACKED_HEIGHT, -}; -pub use openvm_stark_sdk::config::{ - DEFAULT_APP_LOG_BLOWUP, DEFAULT_APP_L_SKIP, DEFAULT_INTERNAL_LOG_BLOWUP, - DEFAULT_LEAF_LOG_BLOWUP, DEFAULT_ROOT_LOG_BLOWUP, -}; -use serde::{Deserialize, Serialize}; - -// WARNING: These currently serve as both the DEFAULT and MAXIMUM number of -// children for the leaf and internal aggregation layers, as the max number -// of children is a const generic in the recursion circuit. We may change -// these as needed, but note that a disparity in max and actual number of -// leaf/internal children will cause a performance loss. -pub const MAX_NUM_CHILDREN_LEAF: usize = 4; -pub const MAX_NUM_CHILDREN_INTERNAL: usize = 3; - -fn default_system_params() -> SystemParams { - app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT) -} - -#[derive(Clone, Debug, Serialize, Deserialize, derive_new::new)] -pub struct AppConfig { - pub app_vm_config: VC, - #[serde(default = "default_system_params")] - pub system_params: SystemParams, -} - -impl AppConfig { - pub fn standard(params: SystemParams) -> Self { - Self::new(SdkVmConfig::standard(), params) - } - - pub fn riscv64(params: SystemParams) -> Self { - Self::new(SdkVmConfig::riscv64(), params) - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AggregationConfig { - pub params: AggregationSystemParams, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AggregationSystemParams { - pub leaf: SystemParams, - pub internal: SystemParams, -} - -impl Default for AggregationSystemParams { - fn default() -> Self { - Self { - leaf: leaf_params_with_100_bits_security(), - internal: internal_params_with_100_bits_security(), - } - } -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize, Args)] -pub struct AggregationTreeConfig { - /// Each leaf verifier circuit will aggregate this many App VM proofs. - #[arg( - long, - default_value_t = MAX_NUM_CHILDREN_LEAF, - help = "Number of children per leaf verifier circuit", - help_heading = "Aggregation Tree Options" - )] - pub num_children_leaf: usize, - /// Each internal verifier circuit will aggregate this many proofs, - /// where each proof may be of either leaf or internal verifier (self) circuit. - #[arg( - long, - default_value_t = MAX_NUM_CHILDREN_INTERNAL, - help = "Number of children per internal verifier circuit", - help_heading = "Aggregation Tree Options" - )] - pub num_children_internal: usize, -} - -impl Default for AggregationTreeConfig { - fn default() -> Self { - Self { - num_children_leaf: MAX_NUM_CHILDREN_LEAF, - num_children_internal: MAX_NUM_CHILDREN_INTERNAL, - } - } -} - -impl AggregationTreeConfig { - pub const fn deferral() -> Self { - Self { - num_children_leaf: 2, - num_children_internal: 2, - } - } -} - -/// Configuration for the Halo2 proving and wrapper keygen. -#[cfg(feature = "evm-prove")] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Halo2Config { - /// The degree `k` for the wrapper circuit. If `None`, auto-tune to pick the - /// smallest `k` that results in a single advice column. Note: that `k` for - /// the verifier circuit is determined by StaticVerifierShape. - pub wrapper_k: Option, - /// Whether to collect detailed profiling metrics during proving. - pub profiling: bool, -} diff --git a/patches/openvm-sdk/src/error.rs b/patches/openvm-sdk/src/error.rs deleted file mode 100644 index 169eea84..00000000 --- a/patches/openvm-sdk/src/error.rs +++ /dev/null @@ -1,32 +0,0 @@ -use openvm_circuit::arch::{VirtualMachineError, VmVerificationError}; -use openvm_transpiler::transpiler::TranspilerError; -use openvm_verify_stark_host::error::VerifyStarkError; -use thiserror::Error; - -use crate::SC; - -#[derive(Error, Debug)] -pub enum SdkError { - #[error("I/O error: {0}")] - Io(#[from] std::io::Error), - #[error("Failed to build guest: code = {0}")] - BuildFailedWithCode(i32), - #[error("Failed to build guest (OPENVM_SKIP_BUILD is set)")] - BuildFailed, - #[error("SDK must set a transpiler")] - TranspilerNotAvailable, - #[error("Transpiler error: {0}")] - Transpiler(#[from] TranspilerError), - #[error("VM error: {0}")] - Vm(#[from] VirtualMachineError), - #[error("STARK verification failed with error: {0}")] - VerifyStark(#[from] VerifyStarkError), - #[error("Other error: {0}")] - Other(#[from] eyre::Error), -} - -impl From> for SdkError { - fn from(error: VmVerificationError) -> Self { - SdkError::Other(error.into()) - } -} diff --git a/patches/openvm-sdk/src/fs.rs b/patches/openvm-sdk/src/fs.rs deleted file mode 100644 index 535deb38..00000000 --- a/patches/openvm-sdk/src/fs.rs +++ /dev/null @@ -1,217 +0,0 @@ -#[cfg(feature = "evm-prove")] -use std::io::{BufReader, BufWriter, Write}; -use std::{ - fs::{create_dir_all, read, write, File}, - path::Path, -}; - -use eyre::{Report, Result}; -use openvm_stark_backend::codec::{Decode, Encode}; -use serde::{de::DeserializeOwned, Serialize}; - -#[cfg(feature = "evm-prove")] -use crate::{ - keygen::Halo2ProvingKey, - types::{EvmHalo2Verifier, EvmVerifierByteCode}, - OPENVM_VERSION, -}; - -pub const EVM_HALO2_VERIFIER_INTERFACE_NAME: &str = "IOpenVmHalo2Verifier.sol"; -pub const EVM_HALO2_VERIFIER_PARENT_NAME: &str = "Halo2Verifier.sol"; -pub const EVM_HALO2_VERIFIER_BASE_NAME: &str = "OpenVmHalo2Verifier.sol"; -pub const EVM_VERIFIER_ARTIFACT_FILENAME: &str = "verifier.bytecode.json"; - -#[cfg(feature = "evm-prove")] -pub fn read_evm_halo2_verifier_from_folder>(folder: P) -> Result { - use std::fs::read_to_string; - - let folder = folder - .as_ref() - .join("src") - .join(format!("v{OPENVM_VERSION}")); - let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME); - let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME); - let interface_path = folder - .join("interfaces") - .join(EVM_HALO2_VERIFIER_INTERFACE_NAME); - let halo2_verifier_code = read_to_string(&halo2_verifier_code_path) - .map_err(|e| read_error(&halo2_verifier_code_path, e.into()))?; - let openvm_verifier_code = read_to_string(&openvm_verifier_code_path) - .map_err(|e| read_error(&openvm_verifier_code_path, e.into()))?; - let interface = - read_to_string(&interface_path).map_err(|e| read_error(&interface_path, e.into()))?; - - let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME); - let artifact: EvmVerifierByteCode = File::open(&artifact_path) - .map_err(|e| read_error(&artifact_path, e.into())) - .and_then(|file| { - serde_json::from_reader(file).map_err(|e| read_error(&artifact_path, e.into())) - })?; - - Ok(EvmHalo2Verifier { - halo2_verifier_code, - openvm_verifier_code, - openvm_verifier_interface: interface, - artifact, - }) -} - -/// Writes three Solidity contracts into the following folder structure: -/// -/// ```text -/// halo2/ -/// └── src/ -/// └── v[OPENVM_VERSION]/ -/// ├── interfaces/ -/// │ └── IOpenVmHalo2Verifier.sol -/// ├── OpenVmHalo2Verifier.sol -/// └── Halo2Verifier.sol -/// ``` -/// -/// If the relevant directories do not exist, they will be created. -#[cfg(feature = "evm-prove")] -pub fn write_evm_halo2_verifier_to_folder>( - verifier: EvmHalo2Verifier, - folder: P, -) -> Result<()> { - let folder = folder - .as_ref() - .join("src") - .join(format!("v{OPENVM_VERSION}")); - if !folder.exists() { - create_dir_all(&folder)?; // Make sure directories exist - } - - let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME); - let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME); - let interface_path = folder - .join("interfaces") - .join(EVM_HALO2_VERIFIER_INTERFACE_NAME); - - if let Some(parent) = interface_path.parent() { - create_dir_all(parent)?; - } - - write(halo2_verifier_code_path, verifier.halo2_verifier_code) - .expect("Failed to write halo2 verifier code"); - write(openvm_verifier_code_path, verifier.openvm_verifier_code) - .expect("Failed to write openvm halo2 verifier code"); - write(interface_path, verifier.openvm_verifier_interface) - .expect("Failed to write openvm halo2 verifier interface"); - - let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME); - serde_json::to_writer(File::create(artifact_path)?, &verifier.artifact)?; - - Ok(()) -} - -pub fn read_object_from_file>(path: P) -> Result { - read_from_file_bitcode(path) -} - -pub fn write_object_to_file>(path: P, data: T) -> Result<()> { - write_to_file_bitcode(path, data) -} - -/// Writes a [`Halo2ProvingKey`] to `path` in the streaming Halo2 pk format. -#[cfg(feature = "evm-prove")] -pub fn write_halo2_pk_to_file>(path: P, halo2_pk: &Halo2ProvingKey) -> Result<()> { - if let Some(parent) = path.as_ref().parent() { - create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?; - } - let file = File::create(&path).map_err(|e| write_error(&path, e.into()))?; - let mut writer = BufWriter::new(file); - halo2_pk - .encode(&mut writer) - .map_err(|e| write_error(&path, e.into()))?; - writer.flush().map_err(|e| write_error(&path, e.into()))?; - Ok(()) -} - -/// Reads a [`Halo2ProvingKey`] written by [`write_halo2_pk_to_file`]. -#[cfg(feature = "evm-prove")] -pub fn read_halo2_pk_from_file>(path: P) -> Result { - let file = File::open(&path).map_err(|e| read_error(&path, e.into()))?; - let mut reader = BufReader::new(file); - Halo2ProvingKey::decode(&mut reader).map_err(|e| read_error(&path, e.into())) -} - -fn read_from_file_bitcode>(path: P) -> Result { - let ret = read(&path) - .map_err(|e| read_error(&path, e.into())) - .and_then(|data| { - bitcode::deserialize(&data).map_err(|e: bitcode::Error| read_error(&path, e.into())) - })?; - Ok(ret) -} - -fn write_to_file_bitcode>(path: P, data: T) -> Result<()> { - if let Some(parent) = path.as_ref().parent() { - create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?; - } - bitcode::serialize(&data) - .map_err(|e| write_error(&path, e.into())) - .and_then(|bytes| write(&path, bytes).map_err(|e| write_error(&path, e.into())))?; - Ok(()) -} - -pub fn read_from_file_json>(path: P) -> Result { - let ret: T = File::open(&path) - .and_then(|file| serde_json::from_reader(file).map_err(|e| e.into())) - .map_err(|e| read_error(&path, e.into()))?; - Ok(ret) -} - -pub fn write_to_file_json>(path: P, data: T) -> Result<()> { - if let Some(parent) = path.as_ref().parent() { - create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?; - } - File::create(&path) - .and_then(|file| serde_json::to_writer_pretty(file, &data).map_err(|e| e.into())) - .map_err(|e| write_error(&path, e.into()))?; - Ok(()) -} - -pub fn read_from_file_bytes>, P: AsRef>(path: P) -> Result { - let bytes = read(&path).map_err(|e| read_error(&path, e.into()))?; - Ok(T::from(bytes)) -} - -pub fn write_to_file_bytes>, P: AsRef>(path: P, data: T) -> Result<()> { - if let Some(parent) = path.as_ref().parent() { - create_dir_all(parent)?; - } - write(path, data.into())?; - Ok(()) -} - -pub fn decode_from_file>(path: P) -> Result { - let reader = &mut File::open(&path).map_err(|e| read_error(&path, e.into()))?; - let ret = T::decode(reader).map_err(|e| read_error(&path, e.into()))?; - Ok(ret) -} - -pub fn encode_to_file>(path: P, data: T) -> Result<()> { - if let Some(parent) = path.as_ref().parent() { - create_dir_all(parent)?; - } - let writer = &mut File::create(path)?; - data.encode(writer)?; - Ok(()) -} - -fn read_error>(path: P, error: Report) -> Report { - eyre::eyre!( - "reading from {} failed with the following error:\n {}", - path.as_ref().display(), - error, - ) -} - -fn write_error>(path: P, error: Report) -> Report { - eyre::eyre!( - "writing to {} failed with the following error:\n {}", - path.as_ref().display(), - error, - ) -} diff --git a/patches/openvm-sdk/src/halo2_params.rs b/patches/openvm-sdk/src/halo2_params.rs deleted file mode 100644 index 3959dfe7..00000000 --- a/patches/openvm-sdk/src/halo2_params.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::{ - collections::HashMap, - io::BufReader, - path::{Path, PathBuf}, - sync::{Arc, Mutex}, -}; - -use openvm_static_verifier::{Halo2Params, Halo2ParamsReader}; - -/// Caching reader for Halo2 KZG parameters. -/// -/// Reads SRS files from a directory and caches them in memory for reuse. -pub struct CacheHalo2ParamsReader { - params_dir: PathBuf, - cached: Mutex>>, -} - -impl Halo2ParamsReader for CacheHalo2ParamsReader { - fn read_params(&self, k: usize) -> Arc { - self.read_params(k) - } -} - -impl CacheHalo2ParamsReader { - pub fn new(params_dir: impl AsRef) -> Self { - Self { - params_dir: params_dir.as_ref().to_path_buf(), - cached: Mutex::new(HashMap::new()), - } - } - - /// Create a reader using the default params directory: `~/.openvm/params/`. - pub fn new_with_default_params_dir() -> Self { - let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string()); - let params_dir = PathBuf::from(home).join(".openvm").join("params"); - Self::new(params_dir) - } - - /// Read the KZG params for a given `k` value, caching the result. - pub fn read_params(&self, k: usize) -> Arc { - let mut cache = self.cached.lock().unwrap(); - if let Some(params) = cache.get(&k) { - return params.clone(); - } - let path = self.params_dir.join(format!("kzg_bn254_{k}.srs")); - let file = std::fs::File::open(&path) - .unwrap_or_else(|e| panic!("Failed to open params file {}: {e}", path.display())); - let mut reader = BufReader::new(file); - - // read_custom with RawBytes format - let params = - Halo2Params::read_custom(&mut reader, halo2_base::halo2_proofs::SerdeFormat::RawBytes) - .unwrap_or_else(|e| panic!("Failed to read params from {}: {e}", path.display())); - - let params = Arc::new(params); - cache.insert(k, params.clone()); - params - } -} diff --git a/patches/openvm-sdk/src/keygen/dummy.rs b/patches/openvm-sdk/src/keygen/dummy.rs deleted file mode 100644 index 6681a9b9..00000000 --- a/patches/openvm-sdk/src/keygen/dummy.rs +++ /dev/null @@ -1,149 +0,0 @@ -use std::sync::Arc; - -use eyre::Result; -use openvm_circuit::arch::{ - instructions::{ - exe::VmExe, instruction::Instruction, program::Program, LocalOpcode, SystemOpcode, - }, - Executor, MeteredExecutor, PreflightExecutor, SystemConfig, VmBuilder, VmExecutionConfig, -}; -use openvm_continuations::{prover::engine_device_ctx, RootSC}; -use openvm_stark_backend::{ - keygen::types::MultiStarkProvingKey, p3_field::PrimeField32, prover::ProvingContext, - StarkEngine, SystemParams, Val, -}; -#[cfg(feature = "evm-prove")] -use { - crate::prover::{EvmProver, RootProver}, - openvm_stark_backend::proof::Proof, -}; - -use crate::{ - prover::{vm::types::VmProvingKey, AggProver, DeferralPathProver, StarkProver}, - StdIn, F, SC, -}; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_continuations::prover::RootGpuProver as RootInnerProver; - type RootE = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine; - } else { - use openvm_continuations::prover::RootCpuProver as RootInnerProver; - type RootE = openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; - } -} - -fn dummy_terminate_exe() -> Arc> { - let dummy_program = Program::::from_instructions(&[Instruction::from_isize( - SystemOpcode::TERMINATE.global_opcode(), - 0, - 0, - 0, - 0, - 0, - )]); - Arc::new(VmExe::new(dummy_program)) -} - -pub fn compute_root_proof_heights( - vm_builder: VB, - app_vm_pk: &VmProvingKey, - agg_prover: Arc, - root_params: SystemParams, - def_prover: Option>, -) -> Result<(Vec, Arc>)> -where - E: StarkEngine, - VB: VmBuilder, - VB::VmConfig: VmExecutionConfig + AsRef, - Val: PrimeField32, - >::Executor: - Executor + MeteredExecutor + PreflightExecutor, -{ - let dummy_exe = dummy_terminate_exe(); - - let system_config = app_vm_pk.vm_config.as_ref(); - let memory_dimensions = system_config.memory_config.memory_dimensions(); - let num_user_pvs = system_config.num_public_values; - - let def_hook_commit = def_prover.as_ref().map(|p| p.def_hook_commit().into()); - - let mut stark_prover = StarkProver::::new( - vm_builder, - app_vm_pk, - dummy_exe, - agg_prover.clone(), - def_prover, - )?; - stark_prover.set_program_name("root_keygen"); - let (agg_proof, _) = stark_prover.prove(StdIn::default(), &[])?; - - let root_prover = RootInnerProver::new::( - agg_prover.internal_recursive_prover.get_vk(), - agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap() - .commitment - .into(), - root_params, - memory_dimensions, - num_user_pvs, - def_hook_commit, - None, - ); - - let engine = RootE::new(root_prover.get_pk().params.clone()); - let root_proving_ctx: ProvingContext<::PB> = root_prover - .generate_proving_ctx( - agg_proof.inner, - &agg_proof.user_pvs_proof, - agg_proof.deferral_merkle_proofs.as_ref(), - engine_device_ctx(&engine), - ) - .unwrap(); - - let trace_heights = root_proving_ctx - .into_iter() - .map(|(_, air_ctx)| air_ctx.height()) - .collect(); - Ok((trace_heights, root_prover.get_pk())) -} - -/// Generate a dummy root proof for keygen purposes. -/// -/// Runs a trivial TERMINATE-only program through the full EVM prover pipeline -/// (app → aggregation → root) and returns the resulting root proof. -#[cfg(feature = "evm-prove")] -pub fn generate_dummy_root_proof( - vm_builder: VB, - app_vm_pk: &VmProvingKey, - agg_prover: Arc, - def_path_prover: Option>, - root_prover: Arc, -) -> Proof -where - E: StarkEngine, - VB: VmBuilder + Clone, - Val: PrimeField32, - >::Executor: - Executor + MeteredExecutor + PreflightExecutor, -{ - let dummy_exe = dummy_terminate_exe(); - - let mut evm_prover = EvmProver::::new( - vm_builder, - app_vm_pk, - dummy_exe, - agg_prover, - def_path_prover, - root_prover, - None, - ) - .expect("Failed to create dummy EVM prover"); - evm_prover.stark_prover.set_program_name("halo2_keygen"); - - evm_prover - .prove_root(StdIn::default(), &[]) - .expect("Failed to generate dummy root proof") -} diff --git a/patches/openvm-sdk/src/keygen/mod.rs b/patches/openvm-sdk/src/keygen/mod.rs deleted file mode 100644 index 4ecd9114..00000000 --- a/patches/openvm-sdk/src/keygen/mod.rs +++ /dev/null @@ -1,139 +0,0 @@ -#[cfg(feature = "evm-prove")] -use std::io::{self, Read, Write}; -use std::sync::Arc; - -use openvm_circuit::{ - arch::{AirInventoryError, SystemConfig, VmCircuitConfig, U16_CELL_SIZE}, - system::memory::dimensions::MemoryDimensions, -}; -#[cfg(feature = "root-prover")] -use openvm_continuations::RootSC; -#[cfg(feature = "evm-prove")] -use openvm_stark_backend::codec::{Decode, Encode}; -use openvm_stark_backend::{ - keygen::types::{MultiStarkProvingKey, MultiStarkVerifyingKey}, - StarkEngine, -}; -use openvm_stark_sdk::config::baby_bear_poseidon2::{BabyBearPoseidon2CpuEngine, DuplexSponge}; -use serde::{Deserialize, Serialize}; - -use crate::{config::AppConfig, prover::vm::types::VmProvingKey, SC}; - -#[cfg(feature = "root-prover")] -pub mod dummy; -#[cfg(feature = "evm-prove")] -pub mod static_verifier; - -/// This is lightweight to clone as it contains smart pointers to the proving keys. -#[derive(Clone, Serialize, Deserialize)] -pub struct AppProvingKey { - pub app_vm_pk: Arc>, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct AppVerifyingKey { - pub vk: MultiStarkVerifyingKey, - pub memory_dimensions: MemoryDimensions, - pub num_user_pvs: usize, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct AggPrefixProvingKey { - pub leaf: Arc>, - pub internal_for_leaf: Arc>, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct AggProvingKey { - pub prefix: AggPrefixProvingKey, - pub internal_recursive: Arc>, -} - -#[cfg(feature = "root-prover")] -#[derive(Clone, Serialize, Deserialize)] -pub struct RootProvingKey { - pub root_pk: Arc>, - pub trace_heights: Vec, -} - -impl AppProvingKey -where - VC: Clone + VmCircuitConfig + AsRef, -{ - pub fn keygen(config: AppConfig) -> Result { - let app_engine = BabyBearPoseidon2CpuEngine::::new(config.system_params); - let app_vm_pk = { - let vm_pk = config - .app_vm_config - .create_airs()? - .keygen(app_engine.config()); - VmProvingKey { - vm_config: config.app_vm_config.clone(), - vm_pk: Arc::new(vm_pk), - } - }; - Ok(Self { - app_vm_pk: Arc::new(app_vm_pk), - }) - } - - pub fn num_public_values_bytes(&self) -> usize { - self.app_vm_pk.vm_config.as_ref().num_public_values * U16_CELL_SIZE - } - - pub fn get_app_vk(&self) -> AppVerifyingKey { - let system_config = self.app_vm_pk.vm_config.as_ref(); - AppVerifyingKey { - vk: self.app_vm_pk.vm_pk.get_vk(), - memory_dimensions: system_config.memory_config.memory_dimensions(), - num_user_pvs: system_config.num_public_values, - } - } - - pub fn vm_config(&self) -> &VC { - &self.app_vm_pk.vm_config - } - - pub fn app_config(&self) -> AppConfig { - AppConfig { - app_vm_config: self.vm_config().clone(), - system_params: self.app_vm_pk.vm_pk.params.clone(), - } - } -} - -#[cfg(feature = "evm-prove")] -#[derive(Clone)] -pub struct Halo2ProvingKey { - /// Static verifier to verify a stark proof of the root verifier. - pub verifier: Arc, - /// Wrapper circuit to verify static verifier and reduce the verification costs in the final - /// proof. - pub wrapper: Arc, - /// Whether to collect detailed profiling metrics. - pub profiling: bool, -} - -#[cfg(feature = "evm-prove")] -impl Encode for Halo2ProvingKey { - fn encode(&self, writer: &mut W) -> io::Result<()> { - self.profiling.encode(writer)?; - self.verifier.encode(writer)?; - self.wrapper.encode(writer) - } -} - -#[cfg(feature = "evm-prove")] -impl Decode for Halo2ProvingKey { - fn decode(reader: &mut R) -> io::Result { - Ok(Self { - profiling: bool::decode(reader)?, - verifier: Arc::new(openvm_static_verifier::StaticVerifierProvingKey::decode( - reader, - )?), - wrapper: Arc::new(openvm_static_verifier::Halo2WrapperProvingKey::decode( - reader, - )?), - }) - } -} diff --git a/patches/openvm-sdk/src/keygen/perm.rs b/patches/openvm-sdk/src/keygen/perm.rs deleted file mode 100644 index 70e8482b..00000000 --- a/patches/openvm-sdk/src/keygen/perm.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::cmp::Reverse; - -#[cfg(feature = "evm-prove")] -use openvm_continuations::verifier::common::types::SpecialAirIds; - -/// Permutation of the AIR IDs to order them by forced trace heights. -pub(crate) struct AirIdPermutation { - pub perm: Vec, -} - -impl AirIdPermutation { - pub fn compute(heights: &[u32]) -> AirIdPermutation { - let mut height_with_air_id: Vec<_> = heights.iter().copied().enumerate().collect(); - height_with_air_id.sort_by_key(|(_, h)| Reverse(*h)); - AirIdPermutation { - perm: height_with_air_id - .into_iter() - .map(|(a_id, _)| a_id) - .collect(), - } - } - #[cfg(feature = "evm-prove")] - pub fn get_special_air_ids(&self) -> SpecialAirIds { - use openvm_circuit::arch::{BOUNDARY_AIR_ID, CONNECTOR_AIR_ID, PROGRAM_AIR_ID}; - - let perm_len = self.perm.len(); - let mut ret = SpecialAirIds { - program_air_id: perm_len, - connector_air_id: perm_len, - public_values_air_id: perm_len, - }; - for (i, &air_id) in self.perm.iter().enumerate() { - if air_id == PROGRAM_AIR_ID { - ret.program_air_id = i; - } else if air_id == CONNECTOR_AIR_ID { - ret.connector_air_id = i; - } else if air_id == BOUNDARY_AIR_ID { - ret.public_values_air_id = i; - } - } - debug_assert_ne!(ret.program_air_id, perm_len, "Program AIR not found"); - debug_assert_ne!(ret.connector_air_id, perm_len, "Connector AIR not found"); - debug_assert_ne!( - ret.public_values_air_id, perm_len, - "Public Values AIR not found" - ); - ret - } - /// arr[i] <- arr[perm[i]] - pub(crate) fn permute(&self, arr: &mut [T]) { - debug_assert_eq!(arr.len(), self.perm.len()); - let mut perm = self.perm.clone(); - for i in 0..perm.len() { - if perm[i] != i { - let mut curr = i; - loop { - let target = perm[curr]; - perm[curr] = curr; - if perm[target] == target { - break; - } - arr.swap(curr, target); - curr = target; - } - } - } - } -} - -#[cfg(test)] -mod tests { - use crate::keygen::perm::AirIdPermutation; - - #[test] - fn test_air_id_permutation() { - { - let perm = AirIdPermutation { - perm: vec![2, 0, 1, 3], - }; - let mut arr = vec![0, 100, 200, 300]; - perm.permute(&mut arr); - assert_eq!(arr, vec![200, 0, 100, 300]); - } - { - let perm = AirIdPermutation { - perm: vec![0, 1, 2, 3], - }; - let mut arr = vec![0, 100, 200, 300]; - perm.permute(&mut arr); - assert_eq!(arr, vec![0, 100, 200, 300]); - } - } -} diff --git a/patches/openvm-sdk/src/keygen/static_verifier.rs b/patches/openvm-sdk/src/keygen/static_verifier.rs deleted file mode 100644 index 3dfa6ffa..00000000 --- a/patches/openvm-sdk/src/keygen/static_verifier.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::sync::Arc; - -use openvm_continuations::{RootSC, SC}; -use openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey, proof::Proof}; -use openvm_static_verifier::{ - compute_dag_onion_commit, log_heights_per_air_from_proof, Halo2Params, Halo2ParamsReader, - Halo2WrapperProvingKey, StaticVerifierCircuit, StaticVerifierProvingKey, StaticVerifierShape, -}; - -use crate::{config::Halo2Config, keygen::Halo2ProvingKey}; - -/// Generate a [`Halo2ProvingKey`] (static verifier + wrapper) by running a -/// dummy root proof through the pipeline. -/// -/// This is the self-contained keygen flow: -/// 1. Build a [`StaticVerifierProvingKey`] from the root VK and proof shape -/// 2. Generate a dummy snark from the static verifier -/// 3. Build a [`Halo2WrapperProvingKey`] (auto-tuned or fixed `k`) -/// 4. Return the composite [`Halo2ProvingKey`] -#[tracing::instrument(level = "info", fields(group = "halo2_keygen"), skip_all)] -pub fn keygen_halo2( - halo2_config: &Halo2Config, - reader: &impl Halo2ParamsReader, - shape: StaticVerifierShape, - internal_recursive_vk: &MultiStarkVerifyingKey, - root_vk: &MultiStarkVerifyingKey, - dummy_root_proof: &Proof, -) -> Halo2ProvingKey { - let params = reader.read_params(shape.k); - - let verifier = keygen_static_verifier( - ¶ms, - shape, - internal_recursive_vk, - root_vk, - dummy_root_proof, - ); - - let dummy_snark = verifier.generate_dummy_snark(reader); - - let wrapper = if let Some(wrapper_k) = halo2_config.wrapper_k { - Halo2WrapperProvingKey::keygen(&reader.read_params(wrapper_k), dummy_snark) - } else { - Halo2WrapperProvingKey::keygen_auto_tune(reader, dummy_snark) - }; - - Halo2ProvingKey { - verifier: Arc::new(verifier), - wrapper: Arc::new(wrapper), - profiling: halo2_config.profiling, - } -} - -/// Generate a [`StaticVerifierProvingKey`] from a root VK, heights, and a -/// dummy root proof. This is the lower-level keygen without the wrapper. -pub fn keygen_static_verifier( - params: &Halo2Params, - shape: StaticVerifierShape, - internal_recursive_vk: &MultiStarkVerifyingKey, - root_vk: &MultiStarkVerifyingKey, - dummy_root_proof: &Proof, -) -> StaticVerifierProvingKey { - let log_heights = log_heights_per_air_from_proof(dummy_root_proof); - let onion_commit = compute_dag_onion_commit(internal_recursive_vk); - - let circuit = StaticVerifierCircuit::try_new(root_vk.clone(), onion_commit, &log_heights) - .expect("Failed to construct StaticVerifierCircuit"); - - StaticVerifierProvingKey::keygen(params, shape, circuit, dummy_root_proof) -} diff --git a/patches/openvm-sdk/src/lib.rs b/patches/openvm-sdk/src/lib.rs deleted file mode 100644 index c9c74ef6..00000000 --- a/patches/openvm-sdk/src/lib.rs +++ /dev/null @@ -1,882 +0,0 @@ -#![cfg_attr(feature = "tco", allow(incomplete_features))] -#![cfg_attr(feature = "tco", feature(explicit_tail_calls))] - -use std::{ - fs::read, - marker::PhantomData, - path::Path, - sync::{Arc, OnceLock}, -}; - -use config::AppConfig; -use getset::Getters; -use keygen::{AppProvingKey, AppVerifyingKey}; -use openvm_build::{ - build_guest_package, find_unique_executable, get_package, GuestOptions, TargetFilter, -}; -// Re-exports -pub use openvm_build::{cargo_command, get_rustup_toolchain_name}; -pub use openvm_circuit; -use openvm_circuit::{ - arch::{ - execution_mode::Segment, instructions::exe::VmExe, Executor, InitFileGenerator, - MeteredExecutor, PreflightExecutor, VirtualMachineError, VmBuilder, VmExecutionConfig, - VmExecutor, U16_CELL_SIZE, - }, - system::memory::merkle::public_values::extract_public_values, -}; -use openvm_continuations::CommitBytes; -use openvm_sdk_config::{SdkVmConfig, SdkVmCpuBuilder, TranspilerConfig}; -use openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey, StarkEngine, SystemParams}; -use openvm_stark_sdk::config::baby_bear_poseidon2::{ - BabyBearPoseidon2CpuEngine as BabyBearPoseidon2Engine, Digest, -}; -#[cfg(feature = "evm-prove")] -use openvm_static_verifier::StaticVerifierShape; -use openvm_transpiler::{ - elf::Elf, openvm_platform::memory::MEM_SIZE, transpiler::Transpiler, FromElf, -}; -use openvm_verify_stark_host::{ - verify_vm_stark_proof_decoded, - vk::{VerificationBaseline, VmStarkVerifyingKey}, - VmStarkProof, -}; - -use crate::{ - config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig}, - keygen::{AggPrefixProvingKey, AggProvingKey}, - prover::{AggProver, AppProver, DeferralPathProver, StarkProver}, - types::{AppExecutionCommit, ExecutableFormat}, -}; -#[cfg(feature = "evm-prove")] -use crate::{halo2_params::CacheHalo2ParamsReader, keygen::Halo2ProvingKey, prover::Halo2Prover}; -#[cfg(feature = "root-prover")] -use crate::{ - keygen::{dummy::compute_root_proof_heights, RootProvingKey}, - prover::{EvmProver, RootProver}, -}; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_sdk_config::SdkVmGpuBuilder; - use openvm_cuda_backend::BabyBearPoseidon2GpuEngine as GpuBabyBearPoseidon2Engine; - pub use GpuSdk as Sdk; - pub type DefaultStarkEngine = GpuBabyBearPoseidon2Engine; - } else { - pub use CpuSdk as Sdk; - pub type DefaultStarkEngine = BabyBearPoseidon2Engine; - } -} - -pub use openvm_stark_sdk::config::baby_bear_poseidon2::{BabyBearPoseidon2Config as SC, F}; - -pub mod builder; -pub mod compiled; -pub mod config; -pub mod fs; -#[cfg(feature = "evm-prove")] -pub mod halo2_params; -pub mod keygen; -pub mod prover; -#[cfg(feature = "evm-verify")] -mod solidity; -pub mod types; -pub mod util; - -#[cfg(all(test, feature = "root-prover"))] -mod tests; - -mod error; -mod stdin; -pub use compiled::{CompiledExeMetered, CompiledExeMeteredCost, CompiledExePure}; -pub use error::SdkError; -pub use stdin::*; - -pub const OPENVM_VERSION: &str = concat!( - env!("CARGO_PKG_VERSION_MAJOR"), - ".", - env!("CARGO_PKG_VERSION_MINOR") -); - -// The SDK is only generic in the engine for the non-root SC. The root SC is fixed to -// BabyBearPoseidon2RootEngine right now. -/// The SDK provides convenience methods and constructors for provers. -/// -/// A built SDK is an immutable proving environment: user-supplied config, params, and pre-generated -/// keys are fixed after construction. Use [`builder`](Self::builder) for advanced initialization, -/// or [`new`](Self::new) / [`new_without_transpiler`](Self::new_without_transpiler) for the -/// common config-driven paths. -/// -/// Internally, the SDK lazily caches proving state that depends only on the app VM config, -/// aggregation config, root params, and optional pre-generated keys. It does not cache any state -/// that depends on the program executable. -/// -/// Some commonly used methods are: -/// - [`compile_and_execute`](Self::compile_and_execute) -/// - [`prove`](Self::prove) -/// - [`verify_proof`](Self::verify_proof) -#[derive(Getters)] -pub struct GenericSdk -where - E: StarkEngine, - VB: VmBuilder, - VB::VmConfig: VmExecutionConfig, -{ - #[getset(get = "pub")] - app_config: AppConfig, - #[getset(get = "pub")] - agg_config: AggregationConfig, - #[getset(get = "pub")] - agg_tree_config: AggregationTreeConfig, - #[cfg(feature = "root-prover")] - #[getset(get = "pub")] - root_params: SystemParams, - #[cfg(feature = "evm-prove")] - #[getset(get = "pub")] - halo2_shape: StaticVerifierShape, - #[cfg(feature = "evm-prove")] - #[getset(get = "pub")] - halo2_config: config::Halo2Config, - - #[getset(get = "pub")] - app_vm_builder: VB, - - transpiler: Option>, - - /// The `executor` may be used to construct different types of interpreters, given the program, - /// for more specific execution purposes. By default, it is recommended to use the - /// [`execute`](GenericSdk::execute) method. - #[getset(get = "pub")] - executor: VmExecutor, - - app_pk: OnceLock>, - agg_prover: OnceLock>, - #[cfg(feature = "root-prover")] - root_prover: OnceLock>, - - def_path_prover: Option>, - - #[cfg(feature = "evm-prove")] - #[getset(get = "pub")] - halo2_params_reader: CacheHalo2ParamsReader, - #[cfg(feature = "evm-prove")] - halo2_prover: OnceLock, - - _phantom: PhantomData, -} - -pub type CpuSdk = GenericSdk; - -#[cfg(feature = "cuda")] -pub type GpuSdk = GenericSdk; - -impl GenericSdk -where - E: StarkEngine, - VB: VmBuilder + Clone + Default, -{ - /// Creates SDK with a standard configuration that includes a set of default VM extensions - /// loaded. - /// - /// **Note**: To use this configuration, your `openvm.toml` must match, including the order of - /// the moduli and elliptic curve parameters of the respective extensions: - /// The `app_vm_config` field of your `openvm.toml` must exactly match the following: - /// - /// ```toml - #[doc = include_str!("../openvm_standard.toml")] - /// ``` - pub fn standard(app_params: SystemParams, agg_params: AggregationSystemParams) -> Self { - GenericSdk::new(AppConfig::standard(app_params), agg_params).unwrap() - } - - /// Creates SDK with a configuration with RISC-V RV64IM and IO VM extensions loaded. - /// - /// **Note**: To use this configuration, your `openvm.toml` must exactly match the following: - /// - /// ```toml - #[doc = include_str!("../openvm_riscv64.toml")] - /// ``` - pub fn riscv64(app_params: SystemParams, agg_params: AggregationSystemParams) -> Self { - GenericSdk::new(AppConfig::riscv64(app_params), agg_params).unwrap() - } -} - -impl GenericSdk -where - E: StarkEngine, - VB: VmBuilder, -{ - /// Creates SDK custom to the given [AppConfig], with a RISC-V transpiler. - pub fn new( - app_config: AppConfig, - agg_params: AggregationSystemParams, - ) -> Result - where - VB: Default, - VB::VmConfig: TranspilerConfig, - { - Self::builder() - .app_config(app_config) - .agg_params(agg_params) - .build() - } - - /// Creates an SDK custom to the given [AppConfig] without configuring a transpiler. - /// - /// **Note**: This function does not set the transpiler, which must be done separately to - /// support RISC-V ELFs. - pub fn new_without_transpiler( - app_config: AppConfig, - agg_params: AggregationSystemParams, - ) -> Result - where - VB: Default, - { - Self::builder() - .app_config(app_config) - .agg_params(agg_params) - .build_without_transpiler() - } - - /// Returns the def_hook_prover cached commit. - pub fn def_hook_cached_commit(&self) -> Option { - self.def_path_prover - .as_ref() - .map(|p| p.def_hook_cached_commit()) - } - - /// Returns the deferral hook commit derived from the deferral aggregation path. - pub fn def_hook_commit(&self) -> Option { - self.def_path_prover.as_ref().map(|p| p.def_hook_commit()) - } - - /// Builds the guest package located at `pkg_dir`. This function requires that the build target - /// is unique and errors otherwise. Returns the built ELF file decoded in the [Elf] type. - pub fn build>( - &self, - guest_opts: GuestOptions, - pkg_dir: P, - target_filter: &Option, - init_file_name: Option<&str>, // If None, we use "openvm-init.rs" - ) -> Result { - self.app_config - .app_vm_config - .write_to_init_file(pkg_dir.as_ref(), init_file_name)?; - let pkg = get_package(pkg_dir.as_ref()); - let target_dir = match build_guest_package(&pkg, &guest_opts, None, target_filter) { - Ok(target_dir) => target_dir, - Err(Some(code)) => { - return Err(SdkError::BuildFailedWithCode(code)); - } - Err(None) => { - return Err(SdkError::BuildFailed); - } - }; - - let elf_path = - find_unique_executable(pkg_dir, target_dir, target_filter).map_err(SdkError::Other)?; - let data = read(&elf_path)?; - Elf::decode(&data, MEM_SIZE as u32).map_err(SdkError::Other) - } - - /// Transpiler for transpiling RISC-V ELF to OpenVM executable. - pub fn transpiler(&self) -> Result<&Transpiler, SdkError> { - self.transpiler - .as_ref() - .ok_or(SdkError::TranspilerNotAvailable) - } - - /// Normalizes an ELF or executable handle into a shared [`VmExe`]. - pub fn convert_to_exe( - &self, - executable: impl Into, - ) -> Result>, SdkError> { - let executable = executable.into(); - let exe = match executable { - ExecutableFormat::Elf(elf) => { - let transpiler = self.transpiler()?.clone(); - Arc::new(VmExe::from_elf(elf, transpiler)?) - } - ExecutableFormat::VmExe(exe) => Arc::new(exe), - ExecutableFormat::SharedVmExe(exe) => exe, - }; - Ok(exe) - } -} - -// The SDK is only functional for SC = BabyBearPoseidon2Config because that is what recursive -// aggregation supports. -impl GenericSdk -where - E: StarkEngine, - VB: VmBuilder + Clone, - >::Executor: - Executor + MeteredExecutor + PreflightExecutor, -{ - /// Compile `app_exe` and execute it, returning the user public values as bytes. - pub fn compile_and_execute( - &self, - app_exe: impl Into, - inputs: StdIn, - ) -> Result, SdkError> { - let compiled = self.compile(app_exe)?; - self.execute(&compiled, inputs) - } - - /// Compile `app_exe` for pure execution. - #[tracing::instrument(name = "sdk.compile", level = "info", skip_all)] - pub fn compile( - &self, - app_exe: impl Into, - ) -> Result, SdkError> { - let exe = self.convert_to_exe(app_exe)?; - self.executor - .instance(&exe) - .map_err(VirtualMachineError::from) - .map_err(SdkError::from) - } - - /// Load a previously saved pure-mode rvr artifact. No compatibility validation is performed. - #[cfg(feature = "rvr")] - pub fn load_compiled( - &self, - lib_path: &std::path::Path, - app_exe: impl Into, - ) -> Result, SdkError> { - let exe = self.convert_to_exe(app_exe)?; - self.executor - .load_instance(lib_path, &exe) - .map_err(VirtualMachineError::from) - .map_err(SdkError::from) - } - - /// Run a [`CompiledExePure`] against `inputs` and extract the user public values. - #[tracing::instrument(name = "sdk.execute", level = "info", skip_all)] - pub fn execute( - &self, - compiled: &CompiledExePure<'_, F>, - inputs: StdIn, - ) -> Result, SdkError> { - let final_memory = compiled - .execute(inputs, None) - .map_err(VirtualMachineError::from)? - .memory; - let public_values = extract_public_values( - self.executor.config.as_ref().num_public_values * U16_CELL_SIZE, - &final_memory.memory, - ); - Ok(public_values) - } - - /// Executes with segmentation for proof generation. - /// Returns both user public values and segments with instruction counts and trace heights. - pub fn compile_and_execute_metered( - &self, - app_exe: impl Into, - inputs: StdIn, - ) -> Result<(Vec, Vec), SdkError> { - let compiled = self.compile_metered(app_exe)?; - self.execute_metered(&compiled, inputs) - } - - /// Compile `app_exe` for metered execution. The returned [`CompiledExeMetered`] bundles - /// a precomputed [`MeteredCtx`](openvm_circuit::arch::execution_mode::MeteredCtx) so - /// subsequent runs just clone it. - #[tracing::instrument(name = "sdk.compile_metered", level = "info", skip_all)] - pub fn compile_metered( - &self, - app_exe: impl Into, - ) -> Result, SdkError> { - let app_prover = self.app_prover(app_exe)?; - - let vm = app_prover.vm(); - let exe = app_prover.exe(); - - let ctx = vm.build_metered_ctx(&exe); - let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); - let instance = self - .executor - .metered_instance(&exe, &executor_idx_to_air_idx) - .map_err(VirtualMachineError::from)?; - Ok(CompiledExeMetered { instance, ctx }) - } - - /// Load a previously saved metered-mode artifact. The `MeteredCtx` - /// is rebuilt. Caller supplies `app_exe`; no compatibility validation is performed. - #[cfg(feature = "rvr")] - pub fn load_compiled_metered( - &self, - lib_path: &std::path::Path, - app_exe: impl Into, - ) -> Result, SdkError> { - let app_prover = self.app_prover(app_exe)?; - let vm = app_prover.vm(); - let exe = app_prover.exe(); - - let ctx = vm.build_metered_ctx(&exe); - let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); - let instance = self - .executor - .load_metered_instance(lib_path, &exe, &executor_idx_to_air_idx) - .map_err(VirtualMachineError::from)?; - Ok(CompiledExeMetered { instance, ctx }) - } - - /// Run a [`CompiledExeMetered`] against `inputs`. - #[tracing::instrument(name = "sdk.execute_metered", level = "info", skip_all)] - pub fn execute_metered( - &self, - compiled: &CompiledExeMetered<'_>, - inputs: StdIn, - ) -> Result<(Vec, Vec), SdkError> { - let (segments, final_state) = compiled - .instance - .execute_metered(inputs, compiled.ctx.clone()) - .map_err(VirtualMachineError::from)?; - let public_values = extract_public_values( - self.executor.config.as_ref().num_public_values * U16_CELL_SIZE, - &final_state.memory.memory, - ); - - Ok((public_values, segments)) - } - - /// Executes with cost metering to measure computational cost in trace cells. - /// Returns both user public values, and cost along with instruction count. - pub fn compile_and_execute_metered_cost( - &self, - app_exe: impl Into, - inputs: StdIn, - ) -> Result<(Vec, (u64, u64)), SdkError> { - let compiled = self.compile_metered_cost(app_exe)?; - self.execute_metered_cost(&compiled, inputs) - } - - /// Compile `app_exe` for metered-cost execution. See [`Self::compile_metered`]. - #[tracing::instrument(name = "sdk.compile_metered_cost", level = "info", skip_all)] - pub fn compile_metered_cost( - &self, - app_exe: impl Into, - ) -> Result, SdkError> { - let app_prover = self.app_prover(app_exe)?; - - let vm = app_prover.vm(); - let exe = app_prover.exe(); - - let ctx = vm.build_metered_cost_ctx(); - let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); - #[cfg(feature = "rvr")] - let instance = self - .executor - .metered_cost_instance(&exe, &executor_idx_to_air_idx, &ctx.widths) - .map_err(VirtualMachineError::from)?; - #[cfg(not(feature = "rvr"))] - let instance = self - .executor - .metered_cost_instance(&exe, &executor_idx_to_air_idx) - .map_err(VirtualMachineError::from)?; - Ok(CompiledExeMeteredCost { instance, ctx }) - } - - /// Load a previously saved metered-cost-mode artifact. The `MeteredCostCtx` is - /// rebuilt. Caller supplies `app_exe`; no compatibility validation is performed. - #[cfg(feature = "rvr")] - pub fn load_compiled_metered_cost( - &self, - lib_path: &std::path::Path, - app_exe: impl Into, - ) -> Result, SdkError> { - let app_prover = self.app_prover(app_exe)?; - let vm = app_prover.vm(); - let exe = app_prover.exe(); - - let ctx = vm.build_metered_cost_ctx(); - let executor_idx_to_air_idx = vm.executor_idx_to_air_idx(); - let instance = self - .executor - .load_metered_cost_instance(lib_path, &exe, &executor_idx_to_air_idx, &ctx.widths) - .map_err(VirtualMachineError::from)?; - Ok(CompiledExeMeteredCost { instance, ctx }) - } - - /// Run a [`CompiledExeMeteredCost`] against `inputs`. - #[tracing::instrument(name = "sdk.execute_metered_cost", level = "info", skip_all)] - pub fn execute_metered_cost( - &self, - compiled: &CompiledExeMeteredCost<'_>, - inputs: StdIn, - ) -> Result<(Vec, (u64, u64)), SdkError> { - let (ctx, final_state) = compiled - .instance - .execute_metered_cost(inputs, compiled.ctx.clone()) - .map_err(VirtualMachineError::from)?; - let instret = ctx.instret; - let cost = ctx.cost; - - let public_values = extract_public_values( - self.executor.config.as_ref().num_public_values * U16_CELL_SIZE, - &final_state.memory.memory, - ); - - Ok((public_values, (cost, instret))) - } - - // ======================== Proving Methods ============================ - - /// Generates a single aggregate STARK proof of the full program execution of the given - /// `app_exe` with program inputs `inputs`.\ - /// - /// For convenience, this function also returns the [VerificationBaseline], which is a full - /// commitment to the App [VmExe] and aggregation verifiers. It does **not** depend on the - /// `inputs`. It can be generated separately from the proof by creating a - /// [`prover`](Self::prover) and calling - /// [`app_vm_commit`](StarkProver::app_vm_commit). - /// - /// If STARK aggregation is not needed and a proof whose size may grow linearly with the length - /// of the program runtime is desired, create an [`app_prover`](Self::app_prover) and call - /// [`app_prover.prove(inputs)`](AppProver::prove). - pub fn prove( - &self, - app_exe: impl Into, - inputs: StdIn, - def_inputs: &[DeferralInput], - ) -> Result<(VmStarkProof, VerificationBaseline), SdkError> { - let mut prover = self.prover(app_exe)?; - let proof = prover.prove(inputs, def_inputs)?.0; - let baseline = prover.generate_baseline(); - Ok((proof, baseline)) - } - - #[cfg(feature = "evm-prove")] - /// Generates an EVM-verifiable proof for the given executable and inputs. - pub fn prove_evm( - &self, - app_exe: impl Into, - inputs: StdIn, - def_inputs: &[DeferralInput], - ) -> Result { - let app_exe = self.convert_to_exe(app_exe)?; - let mut evm_prover = self.evm_prover(app_exe)?; - let evm_proof = evm_prover.prove_evm(inputs, def_inputs)?; - Ok(evm_proof) - } - - // ========================= Prover Constructors ========================= - - /// This constructor is for generating app proofs that do not require a single aggregate STARK - /// proof of the full program execution. For a single STARK proof, use the - /// [`prove`](Self::prove) method instead. - /// - /// Creates an app prover instance specific to the provided exe. - /// This function will generate the [AppProvingKey] if it doesn't already exist and use it to - /// construct the [AppProver]. - pub fn app_prover( - &self, - exe: impl Into, - ) -> Result, SdkError> { - let exe = self.convert_to_exe(exe)?; - let app_pk = self.app_pk(); - let prover = AppProver::::new(self.app_vm_builder.clone(), &app_pk.app_vm_pk, exe)?; - Ok(prover) - } - - /// Constructs a new [StarkProver] instance for the given executable. - /// This function will generate the [AppProvingKey] if it does not already - /// exist. - pub fn prover( - &self, - app_exe: impl Into, - ) -> Result, SdkError> { - let app_exe = self.convert_to_exe(app_exe)?; - let app_pk = self.app_pk(); - let stark_prover = StarkProver::::new( - self.app_vm_builder.clone(), - &app_pk.app_vm_pk, - app_exe, - self.agg_prover(), - self.def_path_prover.clone(), - )?; - Ok(stark_prover) - } - - #[cfg(feature = "root-prover")] - /// Constructs an [`EvmProver`] for the given executable with only the root prover, generating - /// prerequisite keys, lazily - pub fn evm_prover_without_halo2( - &self, - app_exe: impl Into, - ) -> Result, SdkError> { - let app_exe = self.convert_to_exe(app_exe)?; - let app_pk = self.app_pk(); - let evm_prover = EvmProver::::new( - self.app_vm_builder.clone(), - &app_pk.app_vm_pk, - app_exe, - self.agg_prover(), - self.def_path_prover.clone(), - self.root_prover(), - #[cfg(feature = "evm-prove")] - None, - )?; - Ok(evm_prover) - } - - #[cfg(feature = "root-prover")] - /// Constructs an [`EvmProver`] for the given executable, generating prerequisite keys lazily. - pub fn evm_prover( - &self, - app_exe: impl Into, - ) -> Result, SdkError> { - #[allow(unused_mut)] - let mut evm_prover = self.evm_prover_without_halo2(app_exe)?; - #[cfg(feature = "evm-prove")] - { - evm_prover.halo2_prover = Some(self.halo2_prover()); - } - Ok(evm_prover) - } - - // ===================== Component Prover Constructors ===================== - - /// Returns the cached aggregation prover, generating it on first use if needed. - pub fn agg_prover(&self) -> Arc { - let app_pk = self.app_pk(); - self.agg_prover - .get_or_init(|| { - Arc::new(AggProver::new( - Arc::new(app_pk.app_vm_pk.vm_pk.get_vk()), - self.agg_config.clone(), - self.agg_tree_config, - self.def_hook_cached_commit(), - )) - }) - .clone() - } - - #[cfg(feature = "root-prover")] - /// Returns the cached root prover, generating it on first use if needed. - pub fn root_prover(&self) -> Arc { - self.root_prover - .get_or_init(|| { - let system_config = self.app_config.app_vm_config.as_ref(); - let root_params = self.root_params.clone(); - let app_pk = self.app_pk(); - let agg_prover = self.agg_prover(); - - let (trace_heights, root_pk) = compute_root_proof_heights::( - self.app_vm_builder.clone(), - &app_pk.app_vm_pk, - agg_prover.clone(), - root_params.clone(), - self.def_path_prover.clone(), - ) - .expect("Trace heights did not generate properly"); - - let memory_dimensions = system_config.memory_config.memory_dimensions(); - let num_user_pvs = system_config.num_public_values; - - Arc::new(RootProver::from_pk( - agg_prover.internal_recursive_prover.get_vk(), - agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap() - .commitment - .into(), - root_pk, - memory_dimensions, - num_user_pvs, - self.def_hook_commit(), - Some(trace_heights), - )) - }) - .clone() - } - - #[cfg(feature = "evm-prove")] - /// Returns the cached Halo2 prover, generating it on first use if needed. - pub fn halo2_prover(&self) -> Halo2Prover { - self.halo2_prover - .get_or_init(|| { - use crate::keygen::static_verifier::keygen_halo2; - - let root_prover = self.root_prover(); - let root_vk = root_prover.0.get_vk().as_ref().clone(); - let agg_prover = self.agg_prover(); - - // Generate a dummy root proof by running a trivial program through the pipeline - let dummy_root_proof = keygen::dummy::generate_dummy_root_proof::( - self.app_vm_builder.clone(), - &self.app_pk().app_vm_pk, - agg_prover.clone(), - self.def_path_prover.clone(), - root_prover, - ); - - let halo2_pk = keygen_halo2( - &self.halo2_config, - &self.halo2_params_reader, - self.halo2_shape, - &agg_prover.internal_recursive_prover.get_vk(), - &root_vk, - &dummy_root_proof, - ); - - Halo2Prover::new(self.halo2_params_reader(), halo2_pk) - }) - .clone() - } - - // ======================== Keygen Related Methods ======================== - - /// Generates the app proving key once and caches it. Future calls will return the cached key. - /// - /// # Panics - /// This function will panic if the app keygen fails. - pub fn app_keygen(&self) -> (AppProvingKey, AppVerifyingKey) { - let pk = self.app_pk().clone(); - let vk = pk.get_app_vk(); - (pk, vk) - } - - /// Generates the app proving key once and caches it. Future calls will return the cached key. - /// - /// # Panics - /// This function will panic if the app keygen fails. - pub fn app_pk(&self) -> &AppProvingKey { - // TODO[jpw]: use `get_or_try_init` once it is stable - self.app_pk.get_or_init(|| { - AppProvingKey::keygen(self.app_config.clone()).expect("app_keygen failed") - }) - } - - /// Returns the app verifying key derived from the cached app proving key. - pub fn app_vk(&self) -> AppVerifyingKey { - self.app_pk().get_app_vk() - } - - /// Generates or retrieves the aggregation proving and verifying keys as a pair. - pub fn agg_keygen(&self) -> (AggProvingKey, MultiStarkVerifyingKey) { - let pk = self.agg_pk(); - let vk = self.agg_vk().as_ref().clone(); - (pk, vk) - } - - /// Generates or retrieves the aggregation prefix proving key without the internal-recursive - /// key. - pub fn agg_prefix_pk(&self) -> AggPrefixProvingKey { - if let Some(agg_prover) = self.agg_prover.get() { - return AggPrefixProvingKey { - leaf: agg_prover.leaf_prover.get_pk(), - internal_for_leaf: agg_prover.internal_for_leaf_prover.get_pk(), - }; - } - - let app_pk = self.app_pk(); - AggProver::keygen_prefix( - Arc::new(app_pk.app_vm_pk.vm_pk.get_vk()), - self.agg_config.clone(), - self.def_hook_cached_commit(), - ) - } - - /// Generates or retrieves the full aggregation proving key. - pub fn agg_pk(&self) -> AggProvingKey { - let agg_prover = self.agg_prover(); - AggProvingKey { - prefix: AggPrefixProvingKey { - leaf: agg_prover.leaf_prover.get_pk(), - internal_for_leaf: agg_prover.internal_for_leaf_prover.get_pk(), - }, - internal_recursive: agg_prover.internal_recursive_prover.get_pk(), - } - } - - /// Returns the aggregation verifying key for the recursive aggregation layer. - pub fn agg_vk(&self) -> Arc> { - self.agg_prover().internal_recursive_prover.get_vk() - } - - #[cfg(feature = "root-prover")] - /// Generates or retrieves the root proving key and recorded trace heights. - pub fn root_pk(&self) -> RootProvingKey { - let root_prover = self.root_prover(); - RootProvingKey { - root_pk: root_prover.0.get_pk(), - trace_heights: root_prover.0.get_trace_heights().unwrap_or_default(), - } - } - - /// Generates the Halo2 (static verifier + wrapper) proving key once and caches it. - /// - /// The flow: - /// 1. Get the root VK and internal recursive VK cached commit - /// 2. Generate a dummy root proof via the EVM prover pipeline - /// 3. Keygen the static verifier circuit - /// 4. Generate a dummy snark from the verifier - /// 5. Keygen the wrapper circuit (auto-tuned or fixed k) - #[cfg(feature = "evm-prove")] - pub fn halo2_pk(&self) -> Halo2ProvingKey { - self.halo2_prover().pk() - } - - /// Generates the [`AppExecutionCommit`] for the given executable. - /// - /// This function will generate the app_pk if it does not already exist. - pub fn app_commit( - &self, - app_exe: impl Into, - ) -> Result { - let prover = self.prover(app_exe)?; - Ok(AppExecutionCommit { - app_exe_commit: CommitBytes::from(prover.generate_baseline().app_exe_commit), - app_vm_commit: CommitBytes::from(prover.app_vm_commit()), - }) - } - - // ======================== Verification Methods ======================== - - /// Verifies aggregate STARK proof of VM execution. - /// - /// **Note**: This function does not have any reliance on `self` and does not depend on the app - /// config set in the [Sdk]. - pub fn verify_proof( - agg_vk: MultiStarkVerifyingKey, - baseline: VerificationBaseline, - proof: &VmStarkProof, - ) -> Result<(), SdkError> { - let vk = VmStarkVerifyingKey { - mvk: agg_vk, - baseline, - }; - verify_vm_stark_proof_decoded(&vk, proof)?; - Ok(()) - } - - #[cfg(feature = "evm-verify")] - /// Generates Solidity verifier artifacts for the cached Halo2 proving key. - pub fn generate_halo2_verifier_solidity(&self) -> Result { - solidity::generate_halo2_verifier_solidity(&self.halo2_pk(), &self.halo2_params_reader) - } - - #[cfg(feature = "evm-verify")] - /// Uses the `verify(..)` interface of the `OpenVmHalo2Verifier` contract. - /// - /// Requires the `evm-verify` feature. Internally deploys the verifier bytecode in a local EVM - /// and executes the verification call. If expected_app_commit is provided, it will check the - /// proof's app_commit against it. - pub fn verify_evm_halo2_proof( - openvm_verifier: &types::EvmHalo2Verifier, - evm_proof: types::EvmProof, - expected_app_commit: Option, - ) -> Result { - if let Some(expected_app_commit) = expected_app_commit { - if expected_app_commit != evm_proof.app_commit { - return Err( - eyre::eyre!("EVM proof verification failed: mismatching app commits").into(), - ); - } - } - solidity::verify_evm_halo2_proof(openvm_verifier, evm_proof) - } -} diff --git a/patches/openvm-sdk/src/prover/agg.rs b/patches/openvm-sdk/src/prover/agg.rs deleted file mode 100644 index a63a5346..00000000 --- a/patches/openvm-sdk/src/prover/agg.rs +++ /dev/null @@ -1,484 +0,0 @@ -use std::sync::Arc; - -use eyre::Result; -use itertools::Itertools; -use openvm_circuit::arch::ContinuationVmProof; -use openvm_continuations::{circuit::inner::ProofsType, prover::ChildVkKind}; -use openvm_recursion_circuit::{prelude::Digest, utils::poseidon2_hash_slice}; -use openvm_stark_backend::{ - codec::{Decode, Encode}, - keygen::types::MultiStarkVerifyingKey, - p3_field::PrimeCharacteristicRing, - proof::Proof, -}; -use openvm_stark_sdk::config::baby_bear_poseidon2::{poseidon2_compress_with_capacity, F}; -use openvm_verify_stark_host::{pvs::DeferralPvs, VmStarkProof}; -use tracing::info_span; - -use crate::{ - config::{ - AggregationConfig, AggregationTreeConfig, MAX_NUM_CHILDREN_INTERNAL, MAX_NUM_CHILDREN_LEAF, - }, - keygen::{AggPrefixProvingKey, AggProvingKey}, - prover::deferral::DeferralProof, - SC, -}; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_continuations::prover::InnerGpuProver as InnerAggregationProver; - type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; - } else { - use openvm_continuations::prover::InnerCpuProver as InnerAggregationProver; - type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; - } -} - -pub struct AggProver { - pub leaf_prover: InnerAggregationProver, - pub internal_for_leaf_prover: InnerAggregationProver, - pub internal_recursive_prover: InnerAggregationProver, - pub agg_tree_config: AggregationTreeConfig, -} - -#[derive(Clone)] -pub struct InternalLayerMetadata { - pub internal_recursive_layer: u32, - pub internal_node_idx: u32, - pub proofs_type: ProofsType, -} - -impl AggProver { - pub fn keygen_prefix( - app_or_def_vk: Arc>, - agg_config: AggregationConfig, - def_hook_cached_commit: Option, - ) -> AggPrefixProvingKey { - let leaf_prover = InnerAggregationProver::::new::( - app_or_def_vk, - agg_config.params.leaf.clone(), - false, - def_hook_cached_commit, - ); - let internal_for_leaf_prover = InnerAggregationProver::::new::( - leaf_prover.get_vk(), - agg_config.params.internal, - false, - def_hook_cached_commit, - ); - AggPrefixProvingKey { - leaf: leaf_prover.get_pk(), - internal_for_leaf: internal_for_leaf_prover.get_pk(), - } - } - - #[tracing::instrument(level = "info", fields(group = "agg_keygen"), skip_all)] - pub fn new( - app_or_def_vk: Arc>, - agg_config: AggregationConfig, - agg_tree_config: AggregationTreeConfig, - def_hook_cached_commit: Option, - ) -> Self { - assert!(agg_tree_config.num_children_leaf <= MAX_NUM_CHILDREN_LEAF); - assert!(agg_tree_config.num_children_internal <= MAX_NUM_CHILDREN_INTERNAL); - let leaf_prover = InnerAggregationProver::new::( - app_or_def_vk, - agg_config.params.leaf.clone(), - false, - def_hook_cached_commit, - ); - let internal_for_leaf_prover = InnerAggregationProver::new::( - leaf_prover.get_vk(), - agg_config.params.internal.clone(), - false, - def_hook_cached_commit, - ); - let internal_recursive_prover = InnerAggregationProver::new::( - internal_for_leaf_prover.get_vk(), - agg_config.params.internal.clone(), - true, - def_hook_cached_commit, - ); - Self { - leaf_prover, - internal_for_leaf_prover, - internal_recursive_prover, - agg_tree_config, - } - } - - pub fn from_pk( - app_or_def_vk: Arc>, - agg_pk: AggProvingKey, - agg_tree_config: AggregationTreeConfig, - def_hook_cached_commit: Option, - ) -> Self { - let leaf_prover = InnerAggregationProver::from_pk::( - app_or_def_vk, - agg_pk.prefix.leaf, - false, - def_hook_cached_commit, - ); - let internal_for_leaf_prover = InnerAggregationProver::from_pk::( - leaf_prover.get_vk(), - agg_pk.prefix.internal_for_leaf, - false, - def_hook_cached_commit, - ); - let internal_recursive_prover = InnerAggregationProver::from_pk::( - internal_for_leaf_prover.get_vk(), - agg_pk.internal_recursive, - true, - def_hook_cached_commit, - ); - Self { - leaf_prover, - internal_for_leaf_prover, - internal_recursive_prover, - agg_tree_config, - } - } - - pub fn vm_or_hook_commit(&self) -> Digest { - let app_or_def_vk_commit = self.leaf_prover.get_vk_commit(false); - let leaf_vk_commit = self.internal_for_leaf_prover.get_vk_commit(false); - let internal_for_leaf_vk_commit = self.internal_recursive_prover.get_vk_commit(false); - let components = vec![ - app_or_def_vk_commit.cached_commit, - app_or_def_vk_commit.vk_pre_hash, - leaf_vk_commit.cached_commit, - leaf_vk_commit.vk_pre_hash, - internal_for_leaf_vk_commit.cached_commit, - internal_for_leaf_vk_commit.vk_pre_hash, - ] - .into_flattened(); - poseidon2_hash_slice(&components).0 - } - - pub fn prove_vm( - &self, - continuation_proof: ContinuationVmProof, - ) -> Result<(VmStarkProof, InternalLayerMetadata)> { - // Verify app-layer proofs and generate leaf-layer proofs - let leaf_proofs = info_span!("agg_layer", group = "leaf").in_scope(|| { - continuation_proof - .per_segment - .chunks(self.agg_tree_config.num_children_leaf) - .enumerate() - .map(|(leaf_node_idx, proofs)| { - info_span!("single_leaf_agg", idx = leaf_node_idx).in_scope(|| { - self.leaf_prover - .agg_prove_no_def::(proofs, ChildVkKind::App) - }) - }) - .collect::>>() - })?; - - // Verify leaf-layer proofs and generate internal-for-leaf-layer proofs - let mut internal_node_idx = -1; - let mut internal_proofs = - info_span!("agg_layer", group = "internal_for_leaf").in_scope(|| { - leaf_proofs - .chunks(self.agg_tree_config.num_children_internal) - .map(|proofs| { - internal_node_idx += 1; - info_span!("single_internal_agg", idx = internal_node_idx).in_scope(|| { - self.internal_for_leaf_prover - .agg_prove_no_def::(proofs, ChildVkKind::Standard) - }) - }) - .collect::>>() - })?; - - // Verify internal-for-leaf-layer proofs and generate internal-recursive-layer proofs - internal_proofs = - info_span!("agg_layer", group = "internal_recursive.0").in_scope(|| { - internal_proofs - .chunks(self.agg_tree_config.num_children_internal) - .map(|proofs| { - internal_node_idx += 1; - info_span!("single_internal_agg", idx = internal_node_idx).in_scope(|| { - self.internal_recursive_prover - .agg_prove_no_def::(proofs, ChildVkKind::Standard) - }) - }) - .collect::>>() - })?; - - // Recursively verify internal-layer proofs until only 1 remains - let mut internal_recursive_layer = 1; - while internal_proofs.len() > 1 { - internal_proofs = info_span!( - "agg_layer", - group = format!("internal_recursive.{internal_recursive_layer}") - ) - .in_scope(|| { - internal_proofs - .chunks(self.agg_tree_config.num_children_internal) - .map(|proofs| { - internal_node_idx += 1; - info_span!("single_internal_agg", idx = internal_node_idx).in_scope(|| { - self.internal_recursive_prover - .agg_prove_no_def::(proofs, ChildVkKind::RecursiveSelf) - }) - }) - .collect::>>() - })?; - internal_recursive_layer += 1; - } - - Ok(( - VmStarkProof { - inner: internal_proofs.pop().unwrap(), - user_pvs_proof: continuation_proof.user_public_values, - deferral_merkle_proofs: None, - }, - InternalLayerMetadata { - internal_recursive_layer: internal_recursive_layer as u32, - internal_node_idx: internal_node_idx as u32, - proofs_type: ProofsType::Vm, - }, - )) - } - - pub fn prove_def(&self, input: Vec) -> Result<(DeferralProof, u32)> { - assert!(!input.is_empty()); - assert!(input.len().is_power_of_two()); - - // Leaf round: hook-level → leaf-level - let mut proofs = info_span!("agg_layer", group = "def_leaf") - .in_scope(|| reduce_def_round(input, ChildVkKind::App, &self.leaf_prover))?; - - // Internal-for-leaf round: leaf-level → i4l-level - proofs = info_span!("agg_layer", group = "def_internal_for_leaf").in_scope(|| { - reduce_def_round( - proofs, - ChildVkKind::Standard, - &self.internal_for_leaf_prover, - ) - })?; - - // Internal-recursive round 0: i4l-level → ir-level - proofs = info_span!("agg_layer", group = "def_internal_recursive.0").in_scope(|| { - reduce_def_round( - proofs, - ChildVkKind::Standard, - &self.internal_recursive_prover, - ) - })?; - - // Internal-recursive rounds: ir-level → ir-level until single proof remains - let mut layer = 1; - while proofs.len() > 1 { - proofs = info_span!( - "agg_layer", - group = format!("def_internal_recursive.{layer}") - ) - .in_scope(|| { - reduce_def_round( - proofs, - ChildVkKind::RecursiveSelf, - &self.internal_recursive_prover, - ) - })?; - layer += 1; - } - - Ok((proofs.pop().unwrap(), layer)) - } - - pub fn prove_mixed( - &self, - mut vm_proof: VmStarkProof, - def_proof: DeferralProof, - metadata: &mut InternalLayerMetadata, - mut def_internal_recursive_layer: u32, - ) -> Result { - let DeferralProof::Present(mut def_inner) = def_proof else { - return Ok(vm_proof); - }; - - // Aggregation requires equal child recursion_depth values, so we wrap the - // shallower side until both proofs are at the same internal-recursive depth. - while metadata.internal_recursive_layer < def_internal_recursive_layer { - vm_proof = self.wrap_proof(vm_proof, metadata)?; - } - while def_internal_recursive_layer < metadata.internal_recursive_layer { - def_inner = self.wrap_def_inner(def_inner, def_internal_recursive_layer)?; - def_internal_recursive_layer += 1; - } - - vm_proof.inner = info_span!( - "agg_layer", - group = format!("internal_recursive.{}", metadata.internal_recursive_layer) - ) - .in_scope(|| { - metadata.internal_recursive_layer += 1; - info_span!("single_internal_agg", idx = metadata.internal_node_idx).in_scope(|| { - metadata.internal_node_idx += 1; - self.internal_recursive_prover.agg_prove::( - &[vm_proof.inner, def_inner], - ChildVkKind::RecursiveSelf, - ProofsType::Mix, - None, - ) - }) - })?; - - metadata.proofs_type = ProofsType::Combined; - Ok(vm_proof) - } - - pub fn wrap_proof( - &self, - mut proof: VmStarkProof, - metadata: &mut InternalLayerMetadata, - ) -> Result { - proof.inner = info_span!( - "agg_layer", - group = format!("internal_recursive.{}", metadata.internal_recursive_layer) - ) - .in_scope(|| { - metadata.internal_recursive_layer += 1; - info_span!("single_internal_agg", idx = metadata.internal_node_idx).in_scope(|| { - metadata.internal_node_idx += 1; - self.internal_recursive_prover.agg_prove::( - &[proof.inner], - ChildVkKind::RecursiveSelf, - metadata.proofs_type, - None, - ) - }) - })?; - Ok(proof) - } - - pub(crate) fn wrap_def_inner( - &self, - mut proof: Proof, - def_internal_recursive_layer: u32, - ) -> Result> { - proof = info_span!( - "agg_layer", - group = format!("def_internal_recursive.{def_internal_recursive_layer}") - ) - .in_scope(|| { - self.internal_recursive_prover.agg_prove::( - &[proof], - ChildVkKind::RecursiveSelf, - ProofsType::Deferral, - None, - ) - })?; - Ok(proof) - } -} - -fn reduce_def_round( - proofs: Vec, - kind: ChildVkKind, - prover: &InnerAggregationProver, -) -> Result> { - if proofs.len() == 1 { - // A singleton round can only happen when the entire round has one present input proof. - let DeferralProof::Present(p) = proofs.into_iter().next().unwrap() else { - panic!("singleton deferral round must contain a present proof"); - }; - return Ok(vec![DeferralProof::Present(prover.agg_prove::( - &[p], - kind, - ProofsType::Deferral, - None, - )?)]); - } - - assert!( - proofs.len().is_multiple_of(2), - "non-singleton deferral round must have an even number of proofs" - ); - - let mut next = Vec::with_capacity(proofs.len() / 2); - for (a, b) in proofs.into_iter().tuples() { - let combined = match (a, b) { - (DeferralProof::Present(p0), DeferralProof::Present(p1)) => DeferralProof::Present( - prover.agg_prove::(&[p0, p1], kind, ProofsType::Deferral, None)?, - ), - (DeferralProof::Present(p), DeferralProof::Absent(pvs)) => { - // Absent is the right child (present is left, is_right = false) - DeferralProof::Present(prover.agg_prove::( - &[p], - kind, - ProofsType::Deferral, - Some((pvs, false)), - )?) - } - (DeferralProof::Absent(pvs), DeferralProof::Present(p)) => { - // Absent is the left child (present is right, is_right = true) - DeferralProof::Present(prover.agg_prove::( - &[p], - kind, - ProofsType::Deferral, - Some((pvs, true)), - )?) - } - (DeferralProof::Absent(pvs0), DeferralProof::Absent(pvs1)) => { - debug_assert_eq!(pvs0.depth, pvs1.depth); - debug_assert_eq!(pvs0.node_idx + F::ONE, pvs1.node_idx); - DeferralProof::Absent(DeferralPvs { - initial_acc_hash: poseidon2_compress_with_capacity( - pvs0.initial_acc_hash, - pvs1.initial_acc_hash, - ) - .0, - final_acc_hash: poseidon2_compress_with_capacity( - pvs0.final_acc_hash, - pvs1.final_acc_hash, - ) - .0, - depth: pvs0.depth + F::ONE, - node_idx: pvs0.node_idx.halve(), - }) - } - }; - next.push(combined); - } - Ok(next) -} - -impl Encode for InternalLayerMetadata { - fn encode(&self, writer: &mut W) -> std::io::Result<()> { - self.internal_recursive_layer.encode(writer)?; - self.internal_node_idx.encode(writer)?; - let proofs_type_byte: u8 = match self.proofs_type { - ProofsType::Vm => 0, - ProofsType::Deferral => 1, - ProofsType::Mix => 2, - ProofsType::Combined => 3, - }; - proofs_type_byte.encode(writer) - } -} - -impl Decode for InternalLayerMetadata { - fn decode(reader: &mut R) -> std::io::Result { - let internal_recursive_layer = u32::decode(reader)?; - let internal_node_idx = u32::decode(reader)?; - let proofs_type = match u8::decode(reader)? { - 0 => ProofsType::Vm, - 1 => ProofsType::Deferral, - 2 => ProofsType::Mix, - 3 => ProofsType::Combined, - b => { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("invalid ProofsType byte: {b}"), - )) - } - }; - Ok(Self { - internal_recursive_layer, - internal_node_idx, - proofs_type, - }) - } -} diff --git a/patches/openvm-sdk/src/prover/app.rs b/patches/openvm-sdk/src/prover/app.rs deleted file mode 100644 index 54fef6ed..00000000 --- a/patches/openvm-sdk/src/prover/app.rs +++ /dev/null @@ -1,209 +0,0 @@ -use std::sync::{Arc, OnceLock}; - -use getset::Getters; -use openvm_circuit::{ - arch::{ - hasher::poseidon2::{vm_poseidon2_hasher, Poseidon2Hasher}, - instructions::exe::VmExe, - verify_segments, ContinuationVmProof, ContinuationVmProver, Executor, MeteredExecutor, - PreflightExecutor, VerifiedExecutionPayload, VirtualMachine, VirtualMachineError, - VmBuilder, VmExecutionConfig, VmInstance, VmVerificationError, - }, - system::{ - memory::dimensions::MemoryDimensions, program::trace::compute_exe_commit_from_mem_config, - }, -}; -use openvm_stark_backend::{ - keygen::types::MultiStarkVerifyingKey, p3_field::PrimeField32, prover::ProverBackend, - StarkEngine, Val, -}; -use openvm_stark_sdk::config::baby_bear_poseidon2::Digest; -use tracing::instrument; - -use crate::{ - keygen::AppVerifyingKey, - prover::vm::{new_local_prover, types::VmProvingKey}, - util::check_max_constraint_degrees, - SdkError, StdIn, F, SC, -}; - -#[derive(Getters)] -pub struct AppProver -where - E: StarkEngine, - VB: VmBuilder, -{ - pub program_name: Option, - #[getset(get = "pub")] - instance: VmInstance, - #[getset(get = "pub")] - app_vm_vk: MultiStarkVerifyingKey, - app_exe_commit: OnceLock, -} - -impl AppProver -where - E: StarkEngine, - VB: VmBuilder, - Val: PrimeField32, -{ - /// Creates a new [AppProver] instance. This method will re-commit the `exe` program on device. - /// If a cached version of the program already exists on device, then directly use the - /// [`Self::new_from_instance`] constructor. - /// - /// The `leaf_verifier_program_commit` is the commitment to the program of the leaf verifier - /// that verifies the App VM circuit. It can be found in the `AppProvingKey`. - pub fn new( - vm_builder: VB, - app_vm_pk: &VmProvingKey, - app_exe: Arc>>, - ) -> Result { - let instance = new_local_prover(vm_builder, app_vm_pk, app_exe)?; - let app_vm_vk = app_vm_pk.vm_pk.get_vk(); - Ok(Self::new_from_instance(instance, app_vm_vk)) - } - - pub fn new_from_instance( - instance: VmInstance, - app_vm_vk: MultiStarkVerifyingKey, - ) -> Self { - Self { - program_name: None, - instance, - app_vm_vk, - app_exe_commit: OnceLock::new(), - } - } - - pub fn set_program_name(&mut self, program_name: impl AsRef) -> &mut Self { - self.program_name = Some(program_name.as_ref().to_string()); - self - } - - pub fn with_program_name(mut self, program_name: impl AsRef) -> Self { - self.set_program_name(program_name); - self - } - - pub fn app_program_commit(&self) -> ::Commitment { - *self.instance().program_commitment() - } - - /// Returns commitment to the executable - pub fn app_exe_commit(&self) -> Digest { - *self.app_exe_commit.get_or_init(|| { - compute_exe_commit_from_mem_config( - &self.app_program_commit(), - self.instance.exe(), - &self.instance.vm.config().as_ref().memory_config, - ) - }) - } - - pub fn memory_dimensions(&self) -> MemoryDimensions { - self.instance - .vm - .config() - .as_ref() - .memory_config - .memory_dimensions() - } - - pub fn num_user_pvs(&self) -> usize { - self.instance.vm.config().as_ref().num_public_values - } - - /// Generates proof for every continuation segment - #[instrument( - name = "app_prove", - skip_all, - fields(group = self.program_name.as_ref().unwrap_or(&"app_proof".to_string())) - )] - pub fn prove( - &mut self, - input: StdIn>, - ) -> Result, VirtualMachineError> - where - >>::Executor: Executor> - + MeteredExecutor> - + PreflightExecutor, VB::RecordArena>, - { - check_max_constraint_degrees( - self.vm_config().as_ref(), - self.app_vm_vk.inner.max_constraint_degree(), - ); - let proof = ContinuationVmProver::prove(&mut self.instance, input)?; - #[cfg(debug_assertions)] - let _ = verify_app_proof_inner::( - &self.app_vm_vk, - self.memory_dimensions(), - self.num_user_pvs(), - &proof, - ) - .expect("app proof verification failed"); - Ok(proof) - } - - /// App Exe - pub fn exe(&self) -> Arc>> { - self.instance.exe().clone() - } - - /// App VM - pub fn vm(&self) -> &VirtualMachine { - &self.instance.vm - } - - /// App VM config - pub fn vm_config(&self) -> &VB::VmConfig { - self.instance.vm.config() - } -} - -/// Verifies a ContinuationVmProof and returns the app_exe_commit -pub fn verify_app_proof>( - app_vk: &AppVerifyingKey, - proof: &ContinuationVmProof, -) -> Result { - verify_app_proof_inner::( - &app_vk.vk, - app_vk.memory_dimensions, - app_vk.num_user_pvs, - proof, - ) -} - -/// Verifies a ContinuationVmProof from the borrowed components of an -/// [`AppVerifyingKey`], returning the app_exe_commit. -fn verify_app_proof_inner>( - vk: &MultiStarkVerifyingKey, - memory_dimensions: MemoryDimensions, - num_user_pvs: usize, - proof: &ContinuationVmProof, -) -> Result { - static POSEIDON2_HASHER: OnceLock> = OnceLock::new(); - let engine = E::new(vk.inner.params.clone()); - let VerifiedExecutionPayload { - exe_commit, - final_memory_root, - } = verify_segments(&engine, vk, &proof.per_segment)?; - - if proof.user_public_values.public_values.len() != num_user_pvs { - return Err(SdkError::Other(eyre::eyre!( - "wrong number of user public values (expected: {}, actual: {})", - num_user_pvs, - proof.user_public_values.public_values.len() - ))); - } - - proof - .user_public_values - .verify( - POSEIDON2_HASHER.get_or_init(vm_poseidon2_hasher), - memory_dimensions, - final_memory_root, - ) - .map_err(VmVerificationError::from)?; - - Ok(exe_commit) -} diff --git a/patches/openvm-sdk/src/prover/deferral/circuit.rs b/patches/openvm-sdk/src/prover/deferral/circuit.rs deleted file mode 100644 index 8c4890e9..00000000 --- a/patches/openvm-sdk/src/prover/deferral/circuit.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::{borrow::Borrow, iter::once, sync::Arc}; - -use eyre::Result; -use itertools::Itertools; -use openvm_continuations::{ - circuit::deferral::{hook::DeferralIoCommit, DeferralCircuitPvs, DEF_CIRCUIT_PVS_AIR_ID}, - prover::{DeferralChildVkKind, DeferralCircuitProver}, - SC, -}; -use openvm_recursion_circuit::utils::poseidon2_hash_slice; -use openvm_stark_backend::{keygen::types::MultiStarkProvingKey, proof::Proof, SystemParams}; -use openvm_stark_sdk::config::baby_bear_poseidon2::{Digest, F}; -use openvm_verify_stark_host::pvs::VkCommit; -use tracing::info_span; - -use crate::DeferralInput; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_continuations::prover::DeferralInnerGpuProver as DeferralInnerProver; - type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; - } else { - use openvm_continuations::prover::DeferralInnerCpuProver as DeferralInnerProver; - type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; - } -} - -pub struct SingleDefCircuitProver { - pub def_circuit_prover: Box + Send + Sync>, - pub leaf_prover: DeferralInnerProver, - pub internal_for_leaf_prover: DeferralInnerProver, -} - -pub struct SingleDefCircuitResult { - pub internal_for_leaf_proofs: Vec>, - pub leaf_io_commits: Vec>, -} - -impl SingleDefCircuitProver { - pub fn new + Send + Sync + 'static>( - def_circuit_prover: DP, - leaf_params: SystemParams, - internal_params: SystemParams, - ) -> Self { - let leaf_prover = - DeferralInnerProver::new::(def_circuit_prover.get_vk(), leaf_params, false); - let internal_for_leaf_prover = - DeferralInnerProver::new::(leaf_prover.get_vk(), internal_params, false); - Self { - def_circuit_prover: Box::new(def_circuit_prover), - leaf_prover, - internal_for_leaf_prover, - } - } - - pub fn from_pks + Send + Sync + 'static>( - def_circuit_prover: DP, - leaf_pk: Arc>, - internal_for_leaf_pk: Arc>, - ) -> Self { - let leaf_prover = - DeferralInnerProver::from_pk::(def_circuit_prover.get_vk(), leaf_pk, false); - let internal_for_leaf_prover = - DeferralInnerProver::from_pk::(leaf_prover.get_vk(), internal_for_leaf_pk, false); - Self { - def_circuit_prover: Box::new(def_circuit_prover), - leaf_prover, - internal_for_leaf_prover, - } - } - - pub fn prove(&self, inputs: &DeferralInput) -> Result { - // Generate deferral circuit proofs - let def_proofs = inputs - .byte_vec - .iter() - .map(|input| self.def_circuit_prover.prove(input)) - .collect_vec(); - - // Extract leaf IO commits from the deferral circuit proofs - let leaf_io_commits = def_proofs - .iter() - .map(|proof| { - let pvs: &DeferralCircuitPvs = proof.public_values[DEF_CIRCUIT_PVS_AIR_ID] - .as_slice() - .borrow(); - let commit_values = once(pvs.input_commit) - .chain( - proof - .trace_vdata - .iter() - .flatten() - .flat_map(|vdata| vdata.cached_commitments.iter().copied()), - ) - .flatten() - .collect_vec(); - let folded_input_commit = poseidon2_hash_slice(&commit_values).0; - (folded_input_commit, pvs.output_commit) - }) - .collect(); - - // Verify def-layer proofs and generate leaf-layer proofs - let child_merkle_depth = (def_proofs.len() != 1).then_some(0); - let leaf_proofs = info_span!("agg_layer", group = "def_leaf").in_scope(|| { - def_proofs - .chunks(2) - .enumerate() - .map(|(leaf_node_idx, proofs)| { - info_span!("single_leaf_agg", idx = leaf_node_idx).in_scope(|| { - self.leaf_prover.agg_prove::( - proofs, - DeferralChildVkKind::DeferralCircuit, - child_merkle_depth, - ) - }) - }) - .collect::>>() - })?; - - // Verify leaf-layer proofs and generate internal-for-leaf-layer proofs - let mut internal_node_idx = 0u32; - let child_merkle_depth = (leaf_proofs.len() != 1).then_some(1); - let internal_for_leaf_proofs = info_span!("agg_layer", group = "internal_for_leaf") - .in_scope(|| { - leaf_proofs - .chunks(2) - .map(|proofs| { - let ret = info_span!("single_internal_agg", idx = internal_node_idx) - .in_scope(|| { - self.internal_for_leaf_prover.agg_prove::( - proofs, - DeferralChildVkKind::DeferralAggregation, - child_merkle_depth, - ) - }); - internal_node_idx += 1; - ret - }) - .collect::>>() - })?; - - Ok(SingleDefCircuitResult { - internal_for_leaf_proofs, - leaf_io_commits, - }) - } - - pub fn circuit_commit(&self, internal_for_leaf_vk_commit: VkCommit) -> Digest { - let def_vk_commit = self.leaf_prover.get_vk_commit(false); - let leaf_vk_commit = self.internal_for_leaf_prover.get_vk_commit(false); - - let vk_commit_components = vec![ - def_vk_commit.cached_commit, - def_vk_commit.vk_pre_hash, - leaf_vk_commit.cached_commit, - leaf_vk_commit.vk_pre_hash, - internal_for_leaf_vk_commit.cached_commit, - internal_for_leaf_vk_commit.vk_pre_hash, - ]; - poseidon2_hash_slice(&vk_commit_components.into_flattened()).0 - } -} diff --git a/patches/openvm-sdk/src/prover/deferral/merkle.rs b/patches/openvm-sdk/src/prover/deferral/merkle.rs deleted file mode 100644 index 2a13f752..00000000 --- a/patches/openvm-sdk/src/prover/deferral/merkle.rs +++ /dev/null @@ -1,65 +0,0 @@ -use openvm_circuit::{ - arch::instructions::DEFERRAL_AS, - system::memory::{dimensions::MemoryDimensions, merkle::MerkleTree}, -}; -use openvm_stark_backend::p3_field::PrimeCharacteristicRing; -use openvm_stark_sdk::config::baby_bear_poseidon2::{DIGEST_SIZE, F}; -use openvm_verify_stark_host::deferral::DeferralMerkleProofs; - -/// Compute deferral merkle proofs from the initial and final memory merkle trees. -/// -/// Proofs have length `overall_height()`. When `depth > 0`, the first `depth` entries -/// are zeros (skipped levels covered by the deferral subtree). The final deferral -/// subtree is required by the verifier to be rooted at node_idx 0. -pub fn compute_deferral_merkle_proofs( - memory_dimensions: MemoryDimensions, - initial_merkle_tree: &MerkleTree, - final_merkle_tree: &MerkleTree, - depth: usize, -) -> DeferralMerkleProofs { - let initial_merkle_proof = - deferral_merkle_proof_from_tree(memory_dimensions, initial_merkle_tree, depth); - let final_merkle_proof = - deferral_merkle_proof_from_tree(memory_dimensions, final_merkle_tree, depth); - DeferralMerkleProofs { - initial_merkle_proof, - final_merkle_proof, - } -} - -/// Extract one side of the deferral merkle proof from a memory merkle tree. -/// -/// Returns a full-length proof (`overall_height()` entries). The first `depth` entries -/// are zeros; the remaining entries are siblings from the tree. -fn deferral_merkle_proof_from_tree( - memory_dimensions: MemoryDimensions, - merkle_tree: &MerkleTree, - depth: usize, -) -> Vec<[F; DIGEST_SIZE]> { - let overall_height = memory_dimensions.overall_height(); - - // Leaf index for DEFERRAL_AS, block_id=0 in the full tree (1-indexed). - let leaf_idx = (1u64 << overall_height) + memory_dimensions.label_to_index((DEFERRAL_AS, 0)); - debug_assert_eq!(leaf_idx % 2, 0); - - // Start at level `depth` above the leaf. When `depth == 0`, the first node in the - // path is the right sibling of the node at `leaf_idx`. - let mut node_idx = if depth == 0 { - leaf_idx + 1 - } else { - leaf_idx >> depth - }; - - // Pad the first `depth` entries with zeros (skipped levels). - let mut proof = vec![[F::ZERO; DIGEST_SIZE]; depth]; - - // Collect siblings from depth up to the root. - while node_idx > 1 { - let sibling_idx = node_idx ^ 1; - proof.push(merkle_tree.get_node(sibling_idx)); - node_idx >>= 1; - } - - assert_eq!(proof.len(), overall_height); - proof -} diff --git a/patches/openvm-sdk/src/prover/deferral/mod.rs b/patches/openvm-sdk/src/prover/deferral/mod.rs deleted file mode 100644 index 0caea5e9..00000000 --- a/patches/openvm-sdk/src/prover/deferral/mod.rs +++ /dev/null @@ -1,264 +0,0 @@ -use std::sync::Arc; - -use eyre::Result; -use itertools::Itertools; -use openvm_continuations::{ - prover::{DeferralChildVkKind, DeferralCircuitProver}, - CommitBytes, SC, -}; -use openvm_deferral_circuit::{DeferralExtension, DeferralFn}; -use openvm_recursion_circuit::utils::poseidon2_hash_slice; -use openvm_stark_backend::{ - keygen::types::MultiStarkProvingKey, - p3_field::{PrimeCharacteristicRing, PrimeField32}, - proof::Proof, - SystemParams, -}; -use openvm_stark_sdk::config::baby_bear_poseidon2::{ - poseidon2_compress_with_capacity, DIGEST_SIZE, F, -}; -use openvm_verify_stark_host::pvs::DeferralPvs; -use tracing::info_span; - -use crate::{config::AggregationConfig, keygen::AggProvingKey, DeferralInput}; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_continuations::prover::DeferralInnerGpuProver as DeferralInnerProver; - use openvm_continuations::prover::DeferralHookGpuProver as DeferralHookProver; - type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; - } else { - use openvm_continuations::prover::DeferralInnerCpuProver as DeferralInnerProver; - use openvm_continuations::prover::DeferralHookCpuProver as DeferralHookProver; - type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; - } -} - -mod circuit; -mod merkle; -mod verify_stark; -pub use circuit::*; -pub use merkle::*; - -pub type DefAggProvingKey = AggProvingKey; - -#[allow(clippy::large_enum_variant)] -#[derive(Clone)] -pub enum DeferralProof { - Present(Proof), - Absent(DeferralPvs), -} - -pub struct DeferralProver { - pub single_circuit_provers: Vec, - pub internal_recursive_prover: DeferralInnerProver, - pub def_hook_prover: DeferralHookProver, -} - -impl DeferralProver { - pub fn new + Send + Sync + 'static>( - def_circuit_prover: DP, - agg_config: AggregationConfig, - hook_params: SystemParams, - ) -> Self { - assert_eq!(def_circuit_prover.get_def_idx(), 0); - let single_circuit_prover = SingleDefCircuitProver::new( - def_circuit_prover, - agg_config.params.leaf, - agg_config.params.internal.clone(), - ); - let internal_recursive_prover = DeferralInnerProver::new::( - single_circuit_prover.internal_for_leaf_prover.get_vk(), - agg_config.params.internal, - true, - ); - let internal_recursive_cached_commit = internal_recursive_prover - .get_vk_commit(true) - .cached_commit - .into(); - let def_hook_prover = DeferralHookProver::new::( - internal_recursive_prover.get_vk(), - internal_recursive_cached_commit, - hook_params, - ); - Self { - single_circuit_provers: vec![single_circuit_prover], - internal_recursive_prover, - def_hook_prover, - } - } - - pub fn from_pks + Send + Sync + 'static>( - def_circuit_prover: DP, - def_agg_pk: DefAggProvingKey, - def_hook_pk: Arc>, - internal_recursive_cached_commit: CommitBytes, - ) -> Self { - assert_eq!(def_circuit_prover.get_def_idx(), 0); - let single_circuit_prover = SingleDefCircuitProver::from_pks( - def_circuit_prover, - def_agg_pk.prefix.leaf, - def_agg_pk.prefix.internal_for_leaf, - ); - let internal_recursive_prover = DeferralInnerProver::from_pk::( - single_circuit_prover.internal_for_leaf_prover.get_vk(), - def_agg_pk.internal_recursive, - false, - ); - let def_hook_prover = DeferralHookProver::from_pk::( - internal_recursive_prover.get_vk(), - internal_recursive_cached_commit, - def_hook_pk, - ); - Self { - single_circuit_provers: vec![single_circuit_prover], - internal_recursive_prover, - def_hook_prover, - } - } - - pub fn with_prover + Send + Sync + 'static>( - mut self, - def_circuit_prover: DP, - ) -> Self { - assert_eq!( - def_circuit_prover.get_def_idx(), - self.single_circuit_provers.len() - ); - let leaf_params = self.single_circuit_provers[0] - .leaf_prover - .get_vk() - .inner - .params - .clone(); - let internal_params = self.internal_recursive_prover.get_vk().inner.params.clone(); - let single_circuit_prover = - SingleDefCircuitProver::new(def_circuit_prover, leaf_params, internal_params); - self.single_circuit_provers.push(single_circuit_prover); - self - } - - pub fn prove(&self, inputs: &[DeferralInput]) -> Result> { - // Generate internal-for-leaf proofs and leaf IO commits per circuit - let per_circuit = self - .single_circuit_provers - .iter() - .zip_eq(inputs) - .map(|(prover, inputs)| prover.prove(inputs)) - .collect::>>()?; - - // For each circuit: do internal recursive aggregation then generate the hook proof - let mut per_circuit = per_circuit - .into_iter() - .enumerate() - .map(|(def_idx, res)| { - let mut proofs = res.internal_for_leaf_proofs; - if proofs.is_empty() { - let def_circuit_commit = self.single_circuit_provers[def_idx] - .circuit_commit(self.internal_recursive_prover.get_vk_commit(false)); - Ok(DeferralProof::Absent(absent_deferral_pvs( - def_idx, - def_circuit_commit, - ))) - } else { - let mut merkle_depth = 2usize; - let mut layer = 0usize; - - // Aggregate internal-for-leaf proofs down to a single proof. - // First pass uses DeferralAggregation (children are i4l proofs); - // subsequent passes use RecursiveSelf (children are ir proofs). - loop { - let is_first = layer == 0; - let child_merkle_depth = if proofs.len() > 1 { - let d = merkle_depth; - merkle_depth += 1; - Some(d) - } else { - None - }; - - proofs = info_span!( - "agg_layer", - group = format!("internal_recursive.{layer}"), - circuit = def_idx - ) - .in_scope(|| { - proofs - .chunks(2) - .enumerate() - .map(|(idx, chunk)| { - let kind = if is_first { - DeferralChildVkKind::DeferralAggregation - } else { - DeferralChildVkKind::RecursiveSelf - }; - info_span!("single_internal_agg", idx = idx).in_scope(|| { - self.internal_recursive_prover.agg_prove::( - chunk, - kind, - child_merkle_depth, - ) - }) - }) - .collect::>>() - })?; - - layer += 1; - if proofs.len() == 1 { - break; - } - } - - // Generate the deferral hook proof - Ok(DeferralProof::Present( - self.def_hook_prover - .prove::(proofs.pop().unwrap(), res.leaf_io_commits)?, - )) - } - }) - .collect::>>()?; - - // Pad returned vector up to a power of two length with absent deferral proofs - let target_length = per_circuit.len().next_power_of_two(); - for def_idx in per_circuit.len()..target_length { - per_circuit.push(DeferralProof::Absent(absent_deferral_pvs( - def_idx, - [F::ZERO; DIGEST_SIZE], - ))); - } - - Ok(per_circuit) - } - - pub fn make_extension(&self, fns: Vec>) -> DeferralExtension { - let vk_commit = self.internal_recursive_prover.get_vk_commit(false); - let def_circuit_commits = self - .single_circuit_provers - .iter() - .map(|p| { - p.circuit_commit(vk_commit) - .iter() - .flat_map(|f| f.to_unique_u32().to_le_bytes()) - .collect::>() - .try_into() - .unwrap() - }) - .collect(); - DeferralExtension { - fns, - def_circuit_commits, - } - } -} - -fn absent_deferral_pvs(def_idx: usize, def_circuit_commit: [F; DIGEST_SIZE]) -> DeferralPvs { - let input_acc_hash = poseidon2_hash_slice(&def_circuit_commit).0; - let output_acc_hash = poseidon2_hash_slice(&[F::ZERO]).0; - let combined_hash = poseidon2_compress_with_capacity(input_acc_hash, output_acc_hash).0; - DeferralPvs { - initial_acc_hash: combined_hash, - final_acc_hash: combined_hash, - depth: F::ONE, - node_idx: F::from_usize(def_idx), - } -} diff --git a/patches/openvm-sdk/src/prover/deferral/verify_stark.rs b/patches/openvm-sdk/src/prover/deferral/verify_stark.rs deleted file mode 100644 index 9409ff64..00000000 --- a/patches/openvm-sdk/src/prover/deferral/verify_stark.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::sync::Arc; - -use openvm_circuit::system::memory::dimensions::MemoryDimensions; -use openvm_continuations::{ - circuit::deferral::dummy::dummy_deferral_circuit_vk, prover::DeferralCircuitProver, SC, -}; -use openvm_stark_backend::{keygen::types::MultiStarkVerifyingKey, proof::Proof, SystemParams}; - -use crate::{ - config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig}, - prover::{AggProver, DeferralPathProver, DeferralProver}, -}; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_verify_stark_circuit::prover::DeferredVerifyGpuProver as VerifyProver; - use openvm_verify_stark_circuit::prover::DeferredVerifyGpuCircuitProver as VerifyCircuitProver; - type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; - } else { - use openvm_verify_stark_circuit::prover::DeferredVerifyCpuProver as VerifyProver; - use openvm_verify_stark_circuit::prover::DeferredVerifyCpuCircuitProver as VerifyCircuitProver; - type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; - } -} - -impl DeferralPathProver { - /// Builds a [`DeferralPathProver`] backed by the verify-stark circuit, configured so an SDK - /// with the given params can recursively verify the VM STARK proofs it produces, including its - /// own deferral-carrying proofs. - /// - /// The deferral-enabled internal-recursive vk and the self-referential `def_hook_commit` are - /// derived internally from a dummy deferral circuit. - pub fn verify_stark( - agg_params: &AggregationSystemParams, - hook_params: SystemParams, - memory_dimensions: MemoryDimensions, - num_user_pvs: usize, - ) -> Self { - // Derive the deferral path's fixed-point artifacts with a cheap dummy deferral circuit. - let dummy = DummyDefCircuitProver { - vk: dummy_deferral_circuit_vk::(agg_params.internal.clone()), - }; - let agg_config = AggregationConfig { - params: agg_params.clone(), - }; - let dummy_deferral_prover = - DeferralProver::new(dummy, agg_config.clone(), hook_params.clone()); - - // Construct the deferral-path AggProver, which can aggregate hook proofs from both the - // dummy DeferralProver above and the verify-stark one below. - let agg_prover = Arc::new(AggProver::new( - dummy_deferral_prover.def_hook_prover.get_vk(), - agg_config.clone(), - AggregationTreeConfig::deferral(), - Some(dummy_deferral_prover.def_hook_prover.get_cached_commit()), - )); - - // The deferral-path aggregation tree's internal-recursive vk is a universal copy of the VM - // internal-recursive vk that a verify-stark circuit verifies. - let ir_vk = agg_prover.internal_recursive_prover.get_vk(); - let ir_cached_commit = agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .expect("internal-recursive prover must expose its self vk pcs data") - .commitment - .into(); - let def_hook_commit = agg_prover.vm_or_hook_commit(); - - // Construct the verify-stark DeferralProver, which should have the same hook vk and cached - // commit as the dummy one. - let deferred_verify_prover = VerifyProver::new::( - ir_vk, - ir_cached_commit, - agg_params.internal.clone(), - memory_dimensions, - num_user_pvs, - Some(def_hook_commit), - 0, - ); - let verify_stark_prover = VerifyCircuitProver::new(deferred_verify_prover); - let deferral_prover = DeferralProver::new(verify_stark_prover, agg_config, hook_params); - - assert_eq!( - deferral_prover.def_hook_prover.get_vk().pre_hash, - dummy_deferral_prover.def_hook_prover.get_vk().pre_hash - ); - assert_eq!( - deferral_prover.def_hook_prover.get_cached_commit(), - dummy_deferral_prover.def_hook_prover.get_cached_commit() - ); - - // Return the deferral-enabled verify-stark DeferralPathProver. - Self::new(Arc::new(deferral_prover), agg_prover) - } -} - -/// A dummy [`DeferralCircuitProver`] that only exposes a trivial verifying key. It exists solely to -/// seed the deferral aggregation chain when deriving the deferral path fixed point; its `prove` -/// method is never called. -struct DummyDefCircuitProver { - vk: Arc>, -} - -impl DeferralCircuitProver for DummyDefCircuitProver { - fn get_vk(&self) -> Arc> { - self.vk.clone() - } - - fn prove(&self, _input_bytes: &[u8]) -> Proof { - unreachable!("DummyDefCircuitProver is only used to derive deferral path artifacts") - } - - fn get_def_idx(&self) -> usize { - 0 - } -} diff --git a/patches/openvm-sdk/src/prover/evm.rs b/patches/openvm-sdk/src/prover/evm.rs deleted file mode 100644 index 1c84e4e2..00000000 --- a/patches/openvm-sdk/src/prover/evm.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::sync::Arc; - -use eyre::Result; -use openvm_circuit::arch::{ - instructions::exe::VmExe, Executor, MeteredExecutor, PreflightExecutor, VmBuilder, - VmExecutionConfig, -}; -use openvm_continuations::RootSC; -use openvm_stark_backend::{p3_field::PrimeField32, proof::Proof, StarkEngine, Val}; -use openvm_verify_stark_host::VmStarkProof; - -#[cfg(feature = "evm-prove")] -use crate::prover::Halo2Prover; -use crate::{ - prover::{ - vm::types::VmProvingKey, AggProver, DeferralPathProver, InternalLayerMetadata, RootProver, - StarkProver, - }, - DeferralInput, StdIn, SC, -}; - -/// EVM prover that produces a root STARK proof with Halo2 wrapping. -/// -/// [`EvmProver::prove_root`] outputs the unwrapped root STARK, while -/// [`EvmProver::prove_root_from_vm_stark_proof`] outputs the unwrapped root STARK from an -/// intermediate STARK proof, for more finegrained separation of work -/// [`EvmProver::prove_evm`] produces an [`EvmProof`](crate::types::EvmProof) -/// suitable for on-chain verification. -pub struct EvmProver -where - E: StarkEngine, - VB: VmBuilder, -{ - pub stark_prover: StarkProver, - pub root_prover: Arc, - #[cfg(feature = "evm-prove")] - pub halo2_prover: Option, -} - -impl EvmProver -where - E: StarkEngine, - VB: VmBuilder + Clone, - Val: PrimeField32, -{ - pub fn new( - vm_builder: VB, - app_vm_pk: &VmProvingKey, - app_exe: Arc>>, - agg_prover: Arc, - def_prover: Option>, - root_prover: Arc, - #[cfg(feature = "evm-prove")] halo2_prover: Option, - ) -> Result { - Ok(Self { - stark_prover: StarkProver::new(vm_builder, app_vm_pk, app_exe, agg_prover, def_prover)?, - root_prover, - #[cfg(feature = "evm-prove")] - halo2_prover, - }) - } - - pub fn prove_root_from_vm_stark_proof( - &mut self, - stark_proof: VmStarkProof, - metadata: &mut InternalLayerMetadata, - ) -> Result> - where - >>::Executor: Executor> - + MeteredExecutor> - + PreflightExecutor, VB::RecordArena>, - { - #[cfg(test)] - { - let agg_vk = self - .stark_prover - .agg_prover - .internal_recursive_prover - .get_vk() - .as_ref() - .clone(); - let baseline = self.stark_prover.generate_baseline(); - crate::GenericSdk::::verify_proof(agg_vk, baseline, &stark_proof)?; - } - - const MAX_ROOT_TRACEGEN_RETRIES: usize = 8; - let agg_prover = &self.stark_prover.agg_prover; - self.root_prover - .prove(stark_proof, MAX_ROOT_TRACEGEN_RETRIES, |p| { - agg_prover.wrap_proof(p, metadata) - }) - } - - pub fn prove_root( - &mut self, - input: StdIn>, - def_inputs: &[DeferralInput], - ) -> Result> - where - >>::Executor: Executor> - + MeteredExecutor> - + PreflightExecutor, VB::RecordArena>, - { - let (stark_proof, mut internal_metadata) = self.stark_prover.prove(input, def_inputs)?; - self.prove_root_from_vm_stark_proof(stark_proof, &mut internal_metadata) - } - - #[cfg(feature = "evm-prove")] - pub fn prove_evm( - &mut self, - input: StdIn>, - def_inputs: &[DeferralInput], - ) -> Result - where - >>::Executor: Executor> - + MeteredExecutor> - + PreflightExecutor, VB::RecordArena>, - { - let root_proof = self.prove_root(input, def_inputs)?; - let evm_proof = self - .halo2_prover - .as_ref() - .unwrap() - .prove_for_evm(&root_proof); - Ok(evm_proof) - } -} diff --git a/patches/openvm-sdk/src/prover/halo2.rs b/patches/openvm-sdk/src/prover/halo2.rs deleted file mode 100644 index 145d3b14..00000000 --- a/patches/openvm-sdk/src/prover/halo2.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::sync::Arc; - -use openvm_continuations::RootSC; -use openvm_stark_backend::proof::Proof; -use openvm_static_verifier::{Halo2Params, Halo2ParamsReader}; -use tracing::{info, info_span}; - -use crate::{keygen::Halo2ProvingKey, types::EvmProof}; - -#[derive(Clone)] -pub struct Halo2Prover { - halo2_pk: Halo2ProvingKey, - verifier_srs: Arc, - wrapper_srs: Arc, -} - -impl Halo2Prover { - pub fn new(reader: &impl Halo2ParamsReader, halo2_pk: Halo2ProvingKey) -> Self { - let verifier_k = halo2_pk.verifier.pinning.metadata.config_params.k; - let wrapper_k = halo2_pk.wrapper.pinning.metadata.config_params.k; - info!(verifier_k, wrapper_k, "Halo2Prover initialized"); - let verifier_srs = reader.read_params(verifier_k); - let wrapper_srs = reader.read_params(wrapper_k); - Self { - halo2_pk, - verifier_srs, - wrapper_srs, - } - } - - pub fn prove_for_evm(&self, root_proof: &Proof) -> EvmProof { - #[cfg(feature = "metrics")] - { - let verifier_k = self.halo2_pk.verifier.pinning.metadata.config_params.k; - let wrapper_k = self.halo2_pk.wrapper.pinning.metadata.config_params.k; - metrics::gauge!("halo2_verifier_k", "group" => "halo2_outer").set(verifier_k as f64); - metrics::gauge!("halo2_wrapper_k", "group" => "halo2_wrapper").set(wrapper_k as f64); - } - let snark = info_span!("total_proof", group = "halo2_outer").in_scope(|| { - self.halo2_pk - .verifier - .prove_wrapped(&self.verifier_srs, root_proof) - }); - info_span!("total_proof", group = "halo2_wrapper").in_scope(|| { - let raw = self - .halo2_pk - .wrapper - .prove_for_evm(&self.wrapper_srs, snark); - EvmProof::from(raw) - }) - } - - pub fn pk(&self) -> Halo2ProvingKey { - self.halo2_pk.clone() - } -} diff --git a/patches/openvm-sdk/src/prover/mod.rs b/patches/openvm-sdk/src/prover/mod.rs deleted file mode 100644 index 3f3129b1..00000000 --- a/patches/openvm-sdk/src/prover/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -mod agg; -mod app; -mod deferral; -#[cfg(feature = "root-prover")] -mod evm; -#[cfg(feature = "evm-prove")] -mod halo2; -#[cfg(feature = "root-prover")] -mod root; -mod stark; -pub mod vm; - -pub use agg::*; -pub use app::*; -pub use deferral::*; -#[cfg(feature = "root-prover")] -pub use evm::*; -#[cfg(feature = "evm-prove")] -pub use halo2::*; -#[cfg(feature = "root-prover")] -pub use root::*; -pub use stark::*; diff --git a/patches/openvm-sdk/src/prover/root.rs b/patches/openvm-sdk/src/prover/root.rs deleted file mode 100644 index cc35c0c4..00000000 --- a/patches/openvm-sdk/src/prover/root.rs +++ /dev/null @@ -1,238 +0,0 @@ -use std::sync::Arc; - -use eyre::Result; -use openvm_circuit::{ - arch::{ - instructions::{ - exe::VmExe, instruction::Instruction, program::Program, LocalOpcode, SystemOpcode, - }, - SystemConfig, - }, - system::memory::dimensions::MemoryDimensions, -}; -use openvm_continuations::{prover::engine_device_ctx, CommitBytes, RootSC, SC}; -use openvm_sdk_config::SdkVmBuilder; -use openvm_stark_backend::{ - keygen::types::{MultiStarkProvingKey, MultiStarkVerifyingKey}, - proof::Proof, - prover::ProvingContext, - StarkEngine, SystemParams, -}; -use openvm_stark_sdk::config::{ - app_params_with_100_bits_security, - baby_bear_poseidon2::{Digest, F}, - MAX_APP_LOG_STACKED_HEIGHT, -}; -use openvm_verify_stark_host::VmStarkProof; -use tracing::info_span; - -use crate::{ - config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}, - keygen::AppProvingKey, - prover::{AggProver, DeferralPathProver, StarkProver}, - StdIn, -}; - -// CPU engine used for `compute_root_proof_heights` — trace heights are structural -// and backend-independent, so we always use the faster CPU engine for that step. -type CpuRootE = - openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_continuations::prover::RootGpuProver as RootInnerProver; - type E = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine; - type ChildE = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; - } else { - use openvm_continuations::prover::RootCpuProver as RootInnerProver; - type E = openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; - type ChildE = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; - } -} - -pub struct RootProver(pub RootInnerProver); - -impl RootProver { - pub fn new( - internal_recursive_vk: Arc>, - internal_recursive_vk_commit: CommitBytes, - system_params: SystemParams, - memory_dimensions: MemoryDimensions, - num_user_pvs: usize, - def_hook_commit: Option, - trace_heights: Option>, - ) -> Self { - let inner = RootInnerProver::new::( - internal_recursive_vk, - internal_recursive_vk_commit, - system_params, - memory_dimensions, - num_user_pvs, - def_hook_commit.map(Into::into), - trace_heights, - ); - Self(inner) - } - - pub fn from_pk( - internal_recursive_vk: Arc>, - internal_recursive_vk_commit: CommitBytes, - pk: Arc>, - memory_dimensions: MemoryDimensions, - num_user_pvs: usize, - def_hook_commit: Option, - trace_heights: Option>, - ) -> Self { - let inner = RootInnerProver::from_pk::( - internal_recursive_vk, - internal_recursive_vk_commit, - pk, - memory_dimensions, - num_user_pvs, - def_hook_commit.map(Into::into), - trace_heights, - ); - Self(inner) - } - - pub fn generate_proving_ctx( - &self, - input: VmStarkProof, - ) -> Option::PB>> { - let engine = E::new(self.0.get_pk().params.clone()); - let ctx = info_span!("tracegen_attempt", group = format!("root")).in_scope(|| { - self.0.generate_proving_ctx( - input.inner, - &input.user_pvs_proof, - input.deferral_merkle_proofs.as_ref(), - engine_device_ctx(&engine), - ) - }); - ctx - } - - pub fn prove_from_ctx( - &self, - ctx: ProvingContext<::PB>, - ) -> Result> { - let proof = info_span!("agg_layer", group = format!("root")) - .in_scope(|| info_span!("root").in_scope(|| self.0.root_prove_from_ctx::(ctx)))?; - Ok(proof) - } - - pub fn prove( - &self, - mut stark_proof: VmStarkProof, - max_retries: usize, - mut wrap: impl FnMut(VmStarkProof) -> Result, - ) -> Result> { - let mut attempt = 0usize; - let ctx = loop { - if let Some(ctx) = self.generate_proving_ctx(stark_proof.clone()) { - break ctx; - } - if attempt >= max_retries { - return Err(eyre::eyre!( - "root tracegen returned None after {max_retries} retries" - )); - } - stark_proof = wrap(stark_proof)?; - attempt += 1; - }; - - // Internal sanity (SDK tests only): a successful tracegen must land at - // exactly the root verifier's fixed, expected trace heights. - #[cfg(test)] - for ((air_idx, air_ctx), expected_height) in ctx - .per_trace - .iter() - .zip(self.0.get_trace_heights().unwrap()) - { - assert_eq!( - air_ctx.height(), - expected_height, - "height mismatch at {air_idx}" - ); - } - - self.prove_from_ctx(ctx) - } -} - -pub fn compute_root_proof_heights( - system_config: SystemConfig, - agg_params: AggregationSystemParams, - agg_tree_config: AggregationTreeConfig, - root_params: SystemParams, - def_prover: Option>, -) -> Result> { - let dummy_program = Program::::from_instructions(&[Instruction::from_isize( - SystemOpcode::TERMINATE.global_opcode(), - 0, - 0, - 0, - 0, - 0, - )]); - let dummy_exe = Arc::new(VmExe::new(dummy_program)); - - let memory_dimensions = system_config.memory_config.memory_dimensions(); - let num_user_pvs = system_config.num_public_values; - - let mut app_config = AppConfig::riscv64(app_params_with_100_bits_security( - MAX_APP_LOG_STACKED_HEIGHT, - )); - app_config.app_vm_config.system.config = system_config; - - let def_hook_cached_commit = def_prover.as_ref().map(|p| p.def_hook_cached_commit()); - let def_hook_commit = def_prover.as_ref().map(|p| p.def_hook_commit().into()); - - let app_pk = AppProvingKey::keygen(app_config)?; - - let agg_prover = Arc::new(AggProver::new( - Arc::new(app_pk.app_vm_pk.vm_pk.get_vk()), - AggregationConfig { params: agg_params }, - agg_tree_config, - def_hook_cached_commit, - )); - - let mut stark_prover = StarkProver::::new( - Default::default(), - &app_pk.app_vm_pk, - dummy_exe, - agg_prover.clone(), - def_prover, - )?; - let (agg_proof, _) = stark_prover.prove(StdIn::default(), &[])?; - - // Use the CPU engine for root keygen + tracegen: trace heights are structural - // and backend-independent, so we avoid expensive GPU BN254 keygen here. - let root_prover = openvm_continuations::prover::RootCpuProver::new::( - agg_prover.internal_recursive_prover.get_vk(), - agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap() - .commitment - .into(), - root_params, - memory_dimensions, - num_user_pvs, - def_hook_commit, - None, - ); - let root_proving_ctx: ProvingContext<::PB> = root_prover - .generate_proving_ctx( - agg_proof.inner, - &agg_proof.user_pvs_proof, - agg_proof.deferral_merkle_proofs.as_ref(), - &(), - ) - .unwrap(); - - let ret = root_proving_ctx - .into_iter() - .map(|(_, air_ctx)| air_ctx.height()) - .collect(); - Ok(ret) -} diff --git a/patches/openvm-sdk/src/prover/stark.rs b/patches/openvm-sdk/src/prover/stark.rs deleted file mode 100644 index 407f6e01..00000000 --- a/patches/openvm-sdk/src/prover/stark.rs +++ /dev/null @@ -1,196 +0,0 @@ -use std::{borrow::Borrow, sync::Arc}; - -use eyre::Result; -use openvm_circuit::{ - arch::{ - hasher::poseidon2::vm_poseidon2_hasher, instructions::exe::VmExe, Executor, - MeteredExecutor, PreflightExecutor, VmBuilder, VmExecutionConfig, - }, - system::memory::merkle::MerkleTree, -}; -use openvm_stark_backend::{p3_field::PrimeField32, StarkEngine, Val}; -use openvm_stark_sdk::config::baby_bear_poseidon2::{Digest, F}; -use openvm_verify_stark_host::{ - pvs::{DeferralPvs, DEF_PVS_AIR_ID}, - vk::VerificationBaseline, - VmStarkProof, -}; - -use crate::{ - prover::{ - deferral::compute_deferral_merkle_proofs, vm::types::VmProvingKey, AggProver, AppProver, - DeferralProver, InternalLayerMetadata, - }, - DeferralInput, StdIn, SC, -}; - -pub struct StarkProver -where - E: StarkEngine, - VB: VmBuilder, -{ - pub app_prover: AppProver, - pub agg_prover: Arc, - pub def_prover: Option>, -} - -#[derive(derive_new::new)] -pub struct DeferralPathProver { - pub deferral_prover: Arc, - pub agg_prover: Arc, -} - -impl StarkProver -where - E: StarkEngine, - VB: VmBuilder, - Val: PrimeField32, -{ - pub fn new( - vm_builder: VB, - app_vm_pk: &VmProvingKey, - app_exe: Arc>>, - agg_prover: Arc, - def_prover: Option>, - ) -> Result { - Ok(Self { - app_prover: AppProver::new(vm_builder, app_vm_pk, app_exe)?, - agg_prover, - def_prover, - }) - } - - pub fn set_program_name(&mut self, program_name: impl AsRef) -> &mut Self { - self.app_prover.set_program_name(program_name); - self - } - - pub fn with_program_name(mut self, program_name: impl AsRef) -> Self { - self.set_program_name(program_name); - self - } - - pub fn prove( - &mut self, - vm_input: StdIn>, - def_inputs: &[DeferralInput], - ) -> Result<(VmStarkProof, InternalLayerMetadata)> - where - >>::Executor: Executor> - + MeteredExecutor> - + PreflightExecutor, VB::RecordArena>, - { - let has_deferrals = self.def_prover.is_some(); - let memory_dimensions = self.app_prover.memory_dimensions(); - - // Build the initial memory merkle tree before proving (needed for deferral proofs). - let initial_merkle_tree = if has_deferrals { - let hasher = vm_poseidon2_hasher(); - let initial_memory = &self - .app_prover - .instance() - .state() - .as_ref() - .expect("initial state should exist before proving") - .memory - .memory; - Some(MerkleTree::from_memory( - initial_memory, - &memory_dimensions, - &hasher, - )) - } else { - None - }; - - let continuation_proof = self.app_prover.prove(vm_input)?; - let (mut stark_proof, mut internal_metadata) = - self.agg_prover.prove_vm(continuation_proof)?; - - if !def_inputs.is_empty() { - let def_prover = self.def_prover.as_ref().unwrap(); - let def_hook_proofs = def_prover.deferral_prover.prove(def_inputs)?; - let (def_proof, def_internal_recursive_layer) = - def_prover.agg_prover.prove_def(def_hook_proofs)?; - stark_proof = self.agg_prover.prove_mixed( - stark_proof, - def_proof, - &mut internal_metadata, - def_internal_recursive_layer, - )?; - } - - // We add one additional internal_recursive layer to reduce the proof size. - const ADDITIONAL_INTERNAL_RECURSIVE_LAYERS: usize = 1; - for _ in 0..ADDITIONAL_INTERNAL_RECURSIVE_LAYERS { - stark_proof = self - .agg_prover - .wrap_proof(stark_proof, &mut internal_metadata)?; - } - - // Generate deferral merkle proofs if deferrals are enabled. - if has_deferrals { - let hasher = vm_poseidon2_hasher(); - let final_memory = &self - .app_prover - .instance() - .state() - .as_ref() - .expect("final state should exist after proving") - .memory - .memory; - let final_merkle_tree = - MerkleTree::from_memory(final_memory, &memory_dimensions, &hasher); - - let def_pvs: &DeferralPvs = stark_proof.inner.public_values[DEF_PVS_AIR_ID] - .as_slice() - .borrow(); - let depth = def_pvs.depth.as_canonical_u32() as usize; - - stark_proof.deferral_merkle_proofs = Some(compute_deferral_merkle_proofs( - memory_dimensions, - initial_merkle_tree.as_ref().unwrap(), - &final_merkle_tree, - depth, - )); - } - - Ok((stark_proof, internal_metadata)) - } - - pub fn generate_baseline(&self) -> VerificationBaseline { - VerificationBaseline { - app_exe_commit: self.app_prover.app_exe_commit(), - memory_dimensions: self.app_prover.memory_dimensions(), - num_user_pvs: self.app_prover.num_user_pvs(), - app_vk_commit: self.agg_prover.leaf_prover.get_vk_commit(false), - leaf_vk_commit: self - .agg_prover - .internal_for_leaf_prover - .get_vk_commit(false), - internal_for_leaf_vk_commit: self - .agg_prover - .internal_recursive_prover - .get_vk_commit(false), - internal_recursive_vk_commit: self - .agg_prover - .internal_recursive_prover - .get_vk_commit(true), - expected_def_hook_commit: self.def_prover.as_ref().map(|dp| dp.def_hook_commit()), - } - } - - pub fn app_vm_commit(&self) -> Digest { - self.agg_prover.vm_or_hook_commit() - } -} - -impl DeferralPathProver { - pub fn def_hook_cached_commit(&self) -> Digest { - self.deferral_prover.def_hook_prover.get_cached_commit() - } - - pub fn def_hook_commit(&self) -> Digest { - self.agg_prover.vm_or_hook_commit() - } -} diff --git a/patches/openvm-sdk/src/prover/vm/mod.rs b/patches/openvm-sdk/src/prover/vm/mod.rs deleted file mode 100644 index 5b77b581..00000000 --- a/patches/openvm-sdk/src/prover/vm/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::sync::Arc; - -use openvm_circuit::arch::{ - instructions::exe::VmExe, VirtualMachine, VirtualMachineError, VmBuilder, VmInstance, -}; -use openvm_stark_backend::{prover::DeviceDataTransporter, StarkEngine, Val}; - -use crate::prover::vm::types::VmProvingKey; - -pub mod types; - -pub fn new_local_prover( - vm_builder: VB, - vm_pk: &VmProvingKey, - exe: Arc>>, -) -> Result, VirtualMachineError> -where - E: StarkEngine, - VB: VmBuilder, -{ - let engine = E::new(vm_pk.get_params()); - let d_pk = engine.device().transport_pk_to_device(&*vm_pk.vm_pk); - let vm = VirtualMachine::new(engine, vm_builder, vm_pk.vm_config.clone(), d_pk)?; - let cached_program_trace = vm.commit_program_on_device(&exe.program); - let instance = VmInstance::new(vm, exe, cached_program_trace)?; - Ok(instance) -} diff --git a/patches/openvm-sdk/src/prover/vm/types.rs b/patches/openvm-sdk/src/prover/vm/types.rs deleted file mode 100644 index f3de4462..00000000 --- a/patches/openvm-sdk/src/prover/vm/types.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::Arc; - -use derivative::Derivative; -use openvm_stark_backend::{keygen::types::MultiStarkProvingKey, SystemParams}; -use serde::{Deserialize, Serialize}; - -/// Proving key for a specific VM. -#[derive(Serialize, Deserialize, Derivative)] -pub struct VmProvingKey { - pub vm_config: VC, - pub vm_pk: Arc>, -} - -impl VmProvingKey { - pub fn get_params(&self) -> SystemParams { - self.vm_pk.params.clone() - } -} diff --git a/patches/openvm-sdk/src/solidity.rs b/patches/openvm-sdk/src/solidity.rs deleted file mode 100644 index 64f5e5fb..00000000 --- a/patches/openvm-sdk/src/solidity.rs +++ /dev/null @@ -1,283 +0,0 @@ -use std::{ - fs::{create_dir_all, write}, - io::Write, - path::Path, - process::{Command, Stdio}, -}; - -use eyre::Context; -use serde_json::{json, Value}; -use tempfile::tempdir; - -use crate::{ - error::SdkError, - fs::{ - EVM_HALO2_VERIFIER_BASE_NAME, EVM_HALO2_VERIFIER_INTERFACE_NAME, - EVM_HALO2_VERIFIER_PARENT_NAME, - }, - types::{EvmHalo2Verifier, EvmVerifierByteCode}, - OPENVM_VERSION, -}; - -const EVM_HALO2_VERIFIER_TEMPLATE: &str = - include_str!("../contracts/template/OpenVmHalo2Verifier.sol"); -const EVM_HALO2_VERIFIER_INTERFACE: &str = - include_str!("../contracts/src/IOpenVmHalo2Verifier.sol"); - -alloy_sol_types::sol! { - #[allow(missing_docs)] - interface IOpenVmHalo2Verifier { - function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view; - } -} - -/// Generate the EVM Halo2 verifier Solidity contract, compile it with solc, and return -/// the verifier artifact. -pub(crate) fn generate_halo2_verifier_solidity( - halo2_pk: &crate::keygen::Halo2ProvingKey, - halo2_params_reader: &crate::halo2_params::CacheHalo2ParamsReader, -) -> Result { - let wrapper_k = halo2_pk.wrapper.pinning.metadata.config_params.k; - let params = halo2_params_reader.read_params(wrapper_k); - - // Generate the base Halo2Verifier Solidity code from snark-verifier - // (via the wrapper circuit, which is what produces the final EVM proof) - let fallback_verifier = halo2_pk.wrapper.generate_fallback_evm_verifier(¶ms); - let halo2_verifier_code = fallback_verifier.sol_code; - - // Compute public values length from the wrapper circuit's instances. - // The wrapper's instances layout is: - // [0..12]: KZG accumulator - // [12]: app_exe_commit - // [13]: app vm commit - // [14..]: user public values - let num_pvs = halo2_pk - .wrapper - .pinning - .metadata - .num_pvs - .first() - .expect("Expected at least one instance column"); - // Subtract 12 (accumulator) + 2 (commits) = 14 to get the number of user - // public value limbs exposed by the static verifier circuit. - let pvs_length = num_pvs - .checked_sub(crate::types::NUM_BN254_ACCUMULATOR + 2) - .expect("Unexpected number of wrapper circuit public values"); - // In rv64 each public value limb occupies U16_CELL_SIZE bytes, while in - // rv32 it occupies one byte. The Solidity contract needs both the number of - // public-value limbs (Fr instances) and the limb byte width. - let pvs_limb_size = openvm_circuit::arch::U16_CELL_SIZE; - let pvs_byte_length = pvs_length * pvs_limb_size; - - assert!( - pvs_byte_length <= 8192, - "OpenVM Halo2 verifier contract does not support more than 8192 public value bytes" - ); - - // PROOF_DATA_LENGTH is now a constant in the template: (12 + 43) * 32 - // Fill out template placeholders - let openvm_verifier_code = EVM_HALO2_VERIFIER_TEMPLATE - .replace("{PUBLIC_VALUES_LENGTH}", &pvs_length.to_string()) - .replace("{PUBLIC_VALUES_LIMB_SIZE}", &pvs_limb_size.to_string()) - .replace("{OPENVM_VERSION}", OPENVM_VERSION); - - // Format Solidity code if forge-fmt is available (requires Rust 1.91+) - let (formatted_interface, formatted_halo2_verifier_code, formatted_openvm_verifier_code) = - format_solidity_sources( - EVM_HALO2_VERIFIER_INTERFACE, - &halo2_verifier_code, - &openvm_verifier_code, - ); - - // Create temp dir - let temp_dir = tempdir() - .wrap_err("Failed to create temp dir") - .map_err(SdkError::Other)?; - let temp_path = temp_dir.path(); - let root_path = Path::new("src").join(format!("v{OPENVM_VERSION}")); - - // Make interfaces dir - let interfaces_path = root_path.join("interfaces"); - - // This will also create the dir for root_path, so no need to explicitly - // create it - create_dir_all(temp_path.join(&interfaces_path))?; - - let interface_file_path = interfaces_path.join(EVM_HALO2_VERIFIER_INTERFACE_NAME); - let parent_file_path = root_path.join(EVM_HALO2_VERIFIER_PARENT_NAME); - let base_file_path = root_path.join(EVM_HALO2_VERIFIER_BASE_NAME); - - // Write the files to the temp dir. This is only for compilation - // purposes. - write(temp_path.join(&interface_file_path), &formatted_interface)?; - write( - temp_path.join(&parent_file_path), - &formatted_halo2_verifier_code, - )?; - write( - temp_path.join(&base_file_path), - &formatted_openvm_verifier_code, - )?; - - // Run solc from the temp dir - let solc_input = json!({ - "language": "Solidity", - "sources": { - interface_file_path.to_str().unwrap(): { - "content": formatted_interface - }, - parent_file_path.to_str().unwrap(): { - "content": formatted_halo2_verifier_code - }, - base_file_path.to_str().unwrap(): { - "content": formatted_openvm_verifier_code - } - }, - "settings": { - "remappings": ["forge-std/=lib/forge-std/src/"], - "optimizer": { - "enabled": true, - "runs": 100000, - "details": { - "constantOptimizer": false, - "yul": false - } - }, - "evmVersion": "paris", - "viaIR": false, - "outputSelection": { - "*": { - "*": ["metadata", "evm.bytecode.object"] - } - } - } - }); - - let mut child = Command::new("solc") - .current_dir(temp_path) - .arg("--standard-json") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .expect("Failed to spawn solc"); - - child - .stdin - .as_mut() - .expect("Failed to open stdin") - .write_all(solc_input.to_string().as_bytes()) - .expect("Failed to write to stdin"); - - let output = child.wait_with_output().expect("Failed to read output"); - - if !output.status.success() { - return Err(SdkError::Other(eyre::eyre!( - "solc exited with status {}: {}", - output.status, - String::from_utf8_lossy(&output.stderr) - ))); - } - - let parsed: Value = - serde_json::from_slice(&output.stdout).map_err(|e| SdkError::Other(e.into()))?; - - let bytecode = parsed - .get("contracts") - .expect("No 'contracts' field found") - .get(format!("src/v{OPENVM_VERSION}/OpenVmHalo2Verifier.sol")) - .unwrap_or_else(|| panic!("No 'src/v{OPENVM_VERSION}/OpenVmHalo2Verifier.sol' field found")) - .get("OpenVmHalo2Verifier") - .expect("No 'OpenVmHalo2Verifier' field found") - .get("evm") - .expect("No 'evm' field found") - .get("bytecode") - .expect("No 'bytecode' field found") - .get("object") - .expect("No 'object' field found") - .as_str() - .expect("No 'object' field found"); - - let bytecode = hex::decode(bytecode).expect("Invalid hex in Binary"); - - let evm_verifier = EvmHalo2Verifier { - halo2_verifier_code: formatted_halo2_verifier_code, - openvm_verifier_code: formatted_openvm_verifier_code, - openvm_verifier_interface: formatted_interface, - artifact: EvmVerifierByteCode { - sol_compiler_version: "0.8.19".to_string(), - sol_compiler_options: solc_input.get("settings").unwrap().to_string(), - bytecode, - }, - }; - Ok(evm_verifier) -} - -/// Verify an EVM Halo2 proof by deploying the verifier bytecode in a local EVM. -pub(crate) fn verify_evm_halo2_proof( - openvm_verifier: &EvmHalo2Verifier, - evm_proof: crate::types::EvmProof, -) -> Result { - // Convert EvmProof → RawEvmProof for the static verifier's evm_verify - let raw_evm_proof: openvm_static_verifier::keygen::RawEvmProof = evm_proof.into(); - let deployment_code = &openvm_verifier.artifact.bytecode; - - let gas_cost = openvm_static_verifier::keygen::evm_verify(deployment_code, &raw_evm_proof) - .map_err(|reason| { - SdkError::Other(eyre::eyre!("EVM proof verification failed: {reason}")) - })?; - - Ok(gas_cost) -} - -/// Format Solidity sources using forge-fmt when available, or return them as-is. -fn format_solidity_sources( - interface: &str, - halo2_verifier: &str, - openvm_verifier: &str, -) -> (String, String, String) { - #[cfg(feature = "evm-verify-fmt")] - { - use forge_fmt::{ - format, FormatterConfig, IntTypes, MultilineFuncHeaderStyle, NumberUnderscore, - QuoteStyle, SingleLineBlockStyle, - }; - - let config = FormatterConfig { - line_length: 120, - tab_width: 4, - bracket_spacing: true, - int_types: IntTypes::Long, - multiline_func_header: MultilineFuncHeaderStyle::AttributesFirst, - quote_style: QuoteStyle::Double, - number_underscore: NumberUnderscore::Thousands, - single_line_statement_blocks: SingleLineBlockStyle::Preserve, - override_spacing: false, - wrap_comments: false, - ignore: vec![], - contract_new_lines: false, - sort_imports: false, - ..Default::default() - }; - - let formatted_interface = format(interface, config.clone()) - .into_result() - .expect("Failed to format interface"); - let formatted_halo2 = format(halo2_verifier, config.clone()) - .into_result() - .expect("Failed to format halo2 verifier code"); - let formatted_openvm = format(openvm_verifier, config) - .into_result() - .expect("Failed to format openvm verifier code"); - - (formatted_interface, formatted_halo2, formatted_openvm) - } - #[cfg(not(feature = "evm-verify-fmt"))] - { - ( - interface.to_string(), - halo2_verifier.to_string(), - openvm_verifier.to_string(), - ) - } -} diff --git a/patches/openvm-sdk/src/stdin.rs b/patches/openvm-sdk/src/stdin.rs deleted file mode 100644 index 409e053a..00000000 --- a/patches/openvm-sdk/src/stdin.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::collections::VecDeque; - -use itertools::Itertools; -use openvm_circuit::arch::{deferral::DeferralState, Streams}; -use openvm_stark_backend::{ - codec::{Decode, Encode}, - p3_field::Field, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Default, Serialize, Deserialize)] -pub struct StdIn { - pub buffer: VecDeque>, - pub deferrals: Vec, -} - -impl StdIn { - pub fn from_bytes(data: &[u8]) -> Self { - let mut ret = Self::default(); - ret.write_bytes(data); - ret - } - - pub fn read(&mut self) -> Option> { - self.buffer.pop_front() - } - - pub fn write(&mut self, data: &T) { - let words = openvm::serde::to_vec(data).unwrap(); - let bytes: Vec = words.into_iter().flat_map(|w| w.to_le_bytes()).collect(); - self.write_bytes(&bytes); - } - - pub fn write_bytes(&mut self, data: &[u8]) { - let field_data = data.iter().map(|b| F::from_u8(*b)).collect(); - self.buffer.push_back(field_data); - } - - pub fn write_field(&mut self, data: &[F]) { - self.buffer.push_back(data.to_vec()); - } -} - -impl From> for Streams { - fn from(mut std_in: StdIn) -> Self { - let mut data = Vec::>::new(); - while let Some(input) = std_in.read() { - data.push(input); - } - let mut ret = Streams::new(data); - ret.deferrals = std_in.deferrals; - ret - } -} - -impl From>> for StdIn { - fn from(inputs: Vec>) -> Self { - let mut ret = StdIn::::default(); - for input in inputs { - ret.write_field(&input); - } - ret - } -} - -#[derive(Clone, Default, Serialize, Deserialize)] -pub struct DeferralInput { - pub byte_vec: Vec>, -} - -impl DeferralInput { - pub fn into_inputs(self) -> Vec { - self.byte_vec - .iter() - .map(|input| I::decode_from_bytes(input).unwrap()) - .collect_vec() - } - - pub fn from_inputs(inputs: &[I]) -> Self { - let byte_vec = inputs - .iter() - .map(|input| input.encode_to_vec().unwrap()) - .collect_vec(); - Self { byte_vec } - } -} diff --git a/patches/openvm-sdk/src/tests.rs b/patches/openvm-sdk/src/tests.rs deleted file mode 100644 index 69067400..00000000 --- a/patches/openvm-sdk/src/tests.rs +++ /dev/null @@ -1,843 +0,0 @@ -use std::{slice::from_ref, sync::Arc}; - -use eyre::Result; -use openvm::platform::memory::MEM_SIZE; -use openvm_circuit::arch::{instructions::DEFERRAL_AS, U16_CELL_SIZE}; -use openvm_continuations::prover::DeferralCircuitProver; -use openvm_deferral_circuit::DeferralFn; -use openvm_stark_backend::{codec::Encode, StarkEngine, SystemParams}; -use openvm_stark_sdk::{ - config::{ - app_params_with_100_bits_security, hook_params_with_100_bits_security, - internal_params_with_100_bits_security, - }, - utils::setup_tracing, -}; -use openvm_transpiler::elf::Elf; -use openvm_verify_stark_circuit::extension::{ - get_deferral_state, get_raw_deferral_results, verify_stark_deferral_fn, -}; -use openvm_verify_stark_host::{ - vk::{VerificationBaseline, VmStarkVerifyingKey}, - VmStarkProof, -}; - -use crate::{ - config::{AggregationConfig, AggregationSystemParams, AppConfig, DEFAULT_APP_L_SKIP}, - prover::{DeferralPathProver, DeferralProof, DeferralProver}, - DeferralInput, Sdk, StdIn, -}; - -cfg_if::cfg_if! { - if #[cfg(feature = "cuda")] { - use openvm_verify_stark_circuit::prover::DeferredVerifyGpuProver as VerifyProver; - use openvm_verify_stark_circuit::prover::DeferredVerifyGpuCircuitProver as VerifyCircuitProver; - type E = openvm_cuda_backend::BabyBearPoseidon2GpuEngine; - type RootE = openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine; - } else { - use openvm_verify_stark_circuit::prover::DeferredVerifyCpuProver as VerifyProver; - use openvm_verify_stark_circuit::prover::DeferredVerifyCpuCircuitProver as VerifyCircuitProver; - type E = openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine; - type RootE = openvm_stark_sdk::config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2CpuEngine; - } -} - -/// Creates a fibonacci SDK with standard test parameters. -fn make_fib_sdk() -> (Sdk, SystemParams, AggregationSystemParams) { - let n_stack = 19; - let app_params = app_params_with_100_bits_security(DEFAULT_APP_L_SKIP + n_stack); - let agg_params = AggregationSystemParams::default(); - let sdk = Sdk::riscv64(app_params.clone(), agg_params.clone()); - (sdk, app_params, agg_params) -} - -/// Generates a fibonacci VM STARK proof using the given SDK. -fn generate_fib_vm_stark_proof(fib_sdk: &Sdk) -> Result<(VmStarkProof, VerificationBaseline)> { - let fib_elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let fib_exe = fib_sdk.convert_to_exe(fib_elf)?; - let n = 100u64; - let mut stdin = StdIn::default(); - stdin.write(&n); - Ok(fib_sdk.prove(fib_exe, stdin, &[])?) -} - -fn make_verify_stark_circuit_prover( - sdk: &Sdk, - def_circuit_params: SystemParams, - def_idx: usize, -) -> VerifyCircuitProver { - let agg_prover = sdk.agg_prover(); - let ir_vk = agg_prover.internal_recursive_prover.get_vk(); - let ir_pcs_data = agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap(); - let system_config = sdk.app_config().app_vm_config.as_ref().clone(); - let memory_dimensions = system_config.memory_config.memory_dimensions(); - let num_user_pvs = system_config.num_public_values; - let deferred_verify_prover = VerifyProver::new::( - ir_vk, - ir_pcs_data.commitment.into(), - def_circuit_params, - memory_dimensions, - num_user_pvs, - None, - def_idx, - ); - VerifyCircuitProver::new(deferred_verify_prover) -} - -/// Builds a DeferralProver from a base SDK with `num_deferral_circuits` copies of the -/// verify-stark deferral circuit. -fn make_deferral_prover_with_count( - sdk: &Sdk, - agg_params: &AggregationSystemParams, - num_deferral_circuits: usize, -) -> DeferralProver { - assert!(num_deferral_circuits > 0); - let def_circuit_params = internal_params_with_100_bits_security(); - let verify_stark_prover = make_verify_stark_circuit_prover(sdk, def_circuit_params.clone(), 0); - let hook_params = hook_params_with_100_bits_security(); - let agg_config = AggregationConfig { - params: agg_params.clone(), - }; - let mut deferral_prover = DeferralProver::new(verify_stark_prover, agg_config, hook_params); - for def_idx in 1..num_deferral_circuits { - deferral_prover = deferral_prover.with_prover(make_verify_stark_circuit_prover( - sdk, - def_circuit_params.clone(), - def_idx, - )); - } - deferral_prover -} - -/// Builds a deferral-enabled riscv64 SDK whose App VM inventory includes the -/// deferral periphery chips (DeferralPoseidon2Chip, count chip, etc.). -fn make_deferral_enabled_sdk( - fib_sdk: &Sdk, - app_params: SystemParams, - agg_params: AggregationSystemParams, -) -> Result { - make_deferral_enabled_sdk_with_count(fib_sdk, app_params, agg_params, 1) -} - -fn make_deferral_enabled_sdk_with_count( - fib_sdk: &Sdk, - app_params: SystemParams, - agg_params: AggregationSystemParams, - num_deferral_circuits: usize, -) -> Result { - let deferral_prover = - make_deferral_prover_with_count(fib_sdk, &agg_params, num_deferral_circuits); - let deferral_fns = (0..num_deferral_circuits) - .map(|_| Arc::new(DeferralFn::new(verify_stark_deferral_fn))) - .collect(); - let deferral_ext = deferral_prover.make_extension(deferral_fns); - - let mut vm_config = openvm_sdk_config::SdkVmConfig::riscv64(); - vm_config.deferral = Some(deferral_ext); - vm_config.system.config.memory_config.addr_spaces[DEFERRAL_AS as usize].num_cells = 1 << 25; - - Ok(Sdk::builder() - .app_config(AppConfig::new(vm_config, app_params)) - .agg_params(agg_params) - .deferral_prover(deferral_prover) - .build()?) -} - -fn make_verify_stark_path_sdk( - app_params: SystemParams, - agg_params: AggregationSystemParams, -) -> Result { - let mut vm_config = openvm_sdk_config::SdkVmConfig::riscv64(); - vm_config.system.config.memory_config.addr_spaces[DEFERRAL_AS as usize].num_cells = 1 << 25; - let memory_dimensions = vm_config.system.config.memory_config.memory_dimensions(); - let num_user_pvs = vm_config.system.config.num_public_values; - - let deferral_path_prover = DeferralPathProver::verify_stark( - &agg_params, - hook_params_with_100_bits_security(), - memory_dimensions, - num_user_pvs, - ); - let deferral_ext = deferral_path_prover - .deferral_prover - .make_extension(vec![Arc::new(DeferralFn::new(verify_stark_deferral_fn))]); - vm_config.deferral = Some(deferral_ext); - - Ok(Sdk::builder() - .app_config(AppConfig::new(vm_config, app_params)) - .agg_params(agg_params) - .deferral_path_prover(deferral_path_prover) - .build()?) -} - -fn make_verify_stark_inputs( - child_sdk: &Sdk, - child_proof: &VmStarkProof, - child_baseline: VerificationBaseline, -) -> Result<(StdIn, DeferralInput)> { - let (stdin, mut def_inputs) = - make_verify_stark_inputs_for_indices(child_sdk, child_proof, child_baseline, &[0], 1)?; - Ok((stdin, def_inputs.pop().unwrap())) -} - -fn make_verify_stark_inputs_for_indices( - child_sdk: &Sdk, - child_proof: &VmStarkProof, - child_baseline: VerificationBaseline, - present_def_indices: &[usize], - num_deferral_circuits: usize, -) -> Result<(StdIn, Vec)> { - let child_vk = VmStarkVerifyingKey { - mvk: child_sdk.agg_vk().as_ref().clone(), - baseline: child_baseline, - }; - - let raw_results = get_raw_deferral_results(&child_vk, from_ref(child_proof))?; - assert_eq!(raw_results.len(), 1); - let input_commit: [u8; 32] = raw_results[0].input.clone().try_into().unwrap(); - let output_raw = &raw_results[0].output_raw; - let app_exe_commit: [u8; 32] = output_raw[..32].try_into().unwrap(); - let app_vm_commit: [u8; 32] = output_raw[32..64].try_into().unwrap(); - - let user_public_values = collapse_user_public_values(&output_raw[64..]); - - let mut stdin = StdIn::default(); - stdin.write(&app_exe_commit); - stdin.write(&app_vm_commit); - stdin.write(&user_public_values); - stdin.write(&input_commit); - stdin.deferrals = vec![Default::default(); num_deferral_circuits]; - - let proof_input = DeferralInput::from_inputs(from_ref(child_proof)); - let mut def_inputs = vec![DeferralInput::default(); num_deferral_circuits]; - for &def_idx in present_def_indices { - assert!(def_idx < num_deferral_circuits); - stdin.deferrals[def_idx] = - get_deferral_state(&child_vk, from_ref(child_proof), def_idx as u32)?; - def_inputs[def_idx] = proof_input.clone(); - } - - Ok((stdin, def_inputs)) -} - -fn collapse_user_public_values(expanded: &[u8]) -> Vec { - const F_NUM_BYTES: usize = core::mem::size_of::(); - assert!(expanded.len().is_multiple_of(F_NUM_BYTES)); - let mut user_public_values = Vec::with_capacity(expanded.len() / F_NUM_BYTES * U16_CELL_SIZE); - for bytes in expanded.chunks_exact(F_NUM_BYTES) { - assert_eq!(&bytes[U16_CELL_SIZE..], &[0; F_NUM_BYTES - U16_CELL_SIZE]); - user_public_values.extend_from_slice(&bytes[..U16_CELL_SIZE]); - } - user_public_values -} - -#[test] -fn collapse_user_public_values_preserves_u16_cells() { - let expanded = [0x34, 0x12, 0, 0, 0xcd, 0xab, 0, 0]; - assert_eq!( - collapse_user_public_values(&expanded), - [0x34, 0x12, 0xcd, 0xab] - ); -} - -/// Builds a deferral-enabled verify-stark SDK from a fibonacci SDK and proof. -/// -/// Returns the SDK, the verify-stark stdin, and the deferral input. -fn make_deferral_sdk( - fib_sdk: &Sdk, - fib_proof: VmStarkProof, - fib_baseline: VerificationBaseline, - app_params: SystemParams, - agg_params: AggregationSystemParams, -) -> Result<(Sdk, StdIn, DeferralInput)> { - let (vs_stdin, def_input) = make_verify_stark_inputs(fib_sdk, &fib_proof, fib_baseline)?; - let vs_sdk = make_deferral_enabled_sdk(fib_sdk, app_params, agg_params)?; - - Ok((vs_sdk, vs_stdin, def_input)) -} - -#[test] -fn test_sdk_fibonacci() -> Result<()> { - setup_tracing(); - let (sdk, _app_params, _agg_params) = make_fib_sdk(); - - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let app_exe = sdk.convert_to_exe(elf)?; - - let n = 1000u64; - let mut stdin = StdIn::default(); - stdin.write(&n); - - #[cfg(not(feature = "evm-verify"))] - { - let mut evm_prover = sdk.evm_prover_without_halo2(app_exe)?; - let proof = evm_prover.prove_root(stdin, &[])?; - let vk = evm_prover.root_prover.0.get_vk(); - let engine = RootE::new(vk.inner.params.clone()); - engine.verify(&vk, &proof)?; - } - #[cfg(feature = "evm-verify")] - { - let app_commit = sdk.app_commit(app_exe.clone())?; - let evm_proof = sdk.prove_evm(app_exe, stdin, &[])?; - let openvm_verifier = sdk.generate_halo2_verifier_solidity()?; - let _gas_cost = Sdk::verify_evm_halo2_proof(&openvm_verifier, evm_proof, Some(app_commit))?; - } - - Ok(()) -} - -#[cfg(feature = "rvr")] -#[test] -fn test_sdk_compiled_pure_save_load_roundtrip() -> Result<()> { - let (sdk, _, _) = make_fib_sdk(); - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let exe = sdk.convert_to_exe(elf)?; - - let mut stdin = StdIn::default(); - stdin.write(&100u64); - - let compiled_a = sdk.compile(exe.clone())?; - let baseline = sdk.execute(&compiled_a, stdin.clone())?; - - let tmp = tempfile::tempdir()?; - let lib_path = compiled_a.save(tmp.path())?; - drop(compiled_a); - - let compiled_b = sdk.load_compiled(&lib_path, exe)?; - let reloaded = sdk.execute(&compiled_b, stdin)?; - - assert_eq!(baseline, reloaded); - Ok(()) -} - -#[cfg(feature = "rvr")] -#[test] -fn test_sdk_compiled_metered_save_load_roundtrip() -> Result<()> { - let (sdk, _, _) = make_fib_sdk(); - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let exe = sdk.convert_to_exe(elf)?; - - let mut stdin = StdIn::default(); - stdin.write(&100u64); - - let compiled_a = sdk.compile_metered(exe.clone())?; - let (baseline_pv, baseline_segments) = sdk.execute_metered(&compiled_a, stdin.clone())?; - - let tmp = tempfile::tempdir()?; - let lib_path = compiled_a.save(tmp.path())?; - drop(compiled_a); - - let compiled_b = sdk.load_compiled_metered(&lib_path, exe)?; - let (reloaded_pv, reloaded_segments) = sdk.execute_metered(&compiled_b, stdin)?; - - assert_eq!(baseline_pv, reloaded_pv); - assert_eq!(baseline_segments.len(), reloaded_segments.len()); - for (a, b) in baseline_segments.iter().zip(reloaded_segments.iter()) { - assert_eq!(a.instret_start, b.instret_start); - assert_eq!(a.num_insns, b.num_insns); - assert_eq!(a.trace_heights, b.trace_heights); - } - Ok(()) -} - -#[cfg(feature = "rvr")] -#[test] -fn test_sdk_compiled_metered_cost_save_load_roundtrip() -> Result<()> { - let (sdk, _, _) = make_fib_sdk(); - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let exe = sdk.convert_to_exe(elf)?; - - let mut stdin = StdIn::default(); - stdin.write(&100u64); - - let compiled_a = sdk.compile_metered_cost(exe.clone())?; - let (baseline_pv, baseline_cost) = sdk.execute_metered_cost(&compiled_a, stdin.clone())?; - - let tmp = tempfile::tempdir()?; - let lib_path = compiled_a.save(tmp.path())?; - drop(compiled_a); - - let compiled_b = sdk.load_compiled_metered_cost(&lib_path, exe)?; - let (reloaded_pv, reloaded_cost) = sdk.execute_metered_cost(&compiled_b, stdin)?; - - assert_eq!(baseline_pv, reloaded_pv); - assert_eq!(baseline_cost, reloaded_cost); - Ok(()) -} - -#[test] -fn test_sdk_compiled_metered_execute() -> Result<()> { - let (sdk, _, _) = make_fib_sdk(); - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let exe = sdk.convert_to_exe(elf)?; - - let mut stdin = StdIn::default(); - stdin.write(&100u64); - - let compiled = sdk.compile_metered(exe)?; - let (_, segments) = sdk.execute_metered(&compiled, stdin)?; - assert!(!segments.is_empty()); - Ok(()) -} - -#[test] -fn test_sdk_compiled_metered_cost_execute() -> Result<()> { - let (sdk, _, _) = make_fib_sdk(); - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let exe = sdk.convert_to_exe(elf)?; - - let mut stdin = StdIn::default(); - stdin.write(&100u64); - - let compiled = sdk.compile_metered_cost(exe)?; - let (_, (_, instret)) = sdk.execute_metered_cost(&compiled, stdin)?; - assert!(instret > 0); - Ok(()) -} - -#[test] -fn test_verify_stark_deferral() -> Result<()> { - setup_tracing(); - let (fib_sdk, app_params, agg_params) = make_fib_sdk(); - let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; - let (vs_sdk, vs_stdin, def_input) = - make_deferral_sdk(&fib_sdk, fib_proof, fib_baseline, app_params, agg_params)?; - - let vs_elf = Elf::decode( - include_bytes!("../programs/examples/verify-stark.elf"), - MEM_SIZE as u32, - )?; - let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; - - let mut evm_prover = vs_sdk.evm_prover_without_halo2(vs_exe)?; - let vs_proof = evm_prover.prove_root(vs_stdin, &[def_input])?; - - let vk = evm_prover.root_prover.0.get_vk(); - let engine = RootE::new(vk.inner.params.clone()); - engine.verify(&vk, &vs_proof)?; - - Ok(()) -} - -#[test] -fn test_verify_many_deferrals() -> Result<()> { - setup_tracing(); - const NUM_DEFERRAL_CIRCUITS: usize = 5; - - let (fib_sdk, app_params, agg_params) = make_fib_sdk(); - let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; - let (vs_stdin, def_inputs) = make_verify_stark_inputs_for_indices( - &fib_sdk, - &fib_proof, - fib_baseline, - &[0, 1, 3, 4], - NUM_DEFERRAL_CIRCUITS, - )?; - let vs_sdk = make_deferral_enabled_sdk_with_count( - &fib_sdk, - app_params, - agg_params, - NUM_DEFERRAL_CIRCUITS, - )?; - - let vs_elf = Elf::decode( - include_bytes!("../programs/examples/verify-many.elf"), - MEM_SIZE as u32, - )?; - let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; - - let (vs_proof, vs_baseline) = vs_sdk.prove(vs_exe, vs_stdin, &def_inputs)?; - assert!( - vs_proof.deferral_merkle_proofs.is_some(), - "verify-many proof must carry deferral merkle proofs", - ); - Sdk::verify_proof(vs_sdk.agg_vk().as_ref().clone(), vs_baseline, &vs_proof)?; - - Ok(()) -} - -#[test] -fn test_verify_stark_with_deferral_child() -> Result<()> { - setup_tracing(); - let (fib_sdk, app_params, agg_params) = make_fib_sdk(); - let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; - let (vs_sdk, vs_stdin, def_input) = - make_deferral_sdk(&fib_sdk, fib_proof, fib_baseline, app_params, agg_params)?; - - let vs_elf = Elf::decode( - include_bytes!("../programs/examples/verify-stark.elf"), - MEM_SIZE as u32, - )?; - let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; - - let (vs_proof, _) = vs_sdk.prove(vs_exe, vs_stdin, &[def_input])?; - assert!( - vs_proof.deferral_merkle_proofs.is_some(), - "deferral-enabled verify-stark child proof must carry deferral merkle proofs", - ); - let expected_def_hook_commit = vs_sdk - .def_hook_commit() - .expect("deferral-enabled SDK should expose a deferral hook commit"); - - // ---- Step 5: Feed the encoded proof through the trait adapter ---- - let vs_agg_prover = vs_sdk.agg_prover(); - let vs_ir_vk = vs_agg_prover.internal_recursive_prover.get_vk(); - let vs_ir_pcs_data = vs_agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap(); - let vs_system_config = vs_sdk.app_config().app_vm_config.as_ref().clone(); - - // This nested verifier is intentionally constructed in deferral-aware mode because the - // verify-stark child proof above was itself produced through a deferral-enabled SDK. - let nested_verify_prover = VerifyProver::new::( - vs_ir_vk, - vs_ir_pcs_data.commitment.into(), - internal_params_with_100_bits_security(), - vs_system_config.memory_config.memory_dimensions(), - vs_system_config.num_public_values, - Some(expected_def_hook_commit), - 0, - ); - let nested_verify_circuit_prover = VerifyCircuitProver::new(nested_verify_prover); - - let encoded_vs_proof = vs_proof.encode_to_vec()?; - let nested_def_proof = nested_verify_circuit_prover.prove(&encoded_vs_proof); - - let vk = nested_verify_circuit_prover.get_vk(); - let engine = E::new(vk.inner.params.clone()); - engine.verify(&vk, &nested_def_proof)?; - - Ok(()) -} - -#[test] -fn test_verify_stark_path_sdk_can_verify_own_proofs() -> Result<()> { - setup_tracing(); - let n_stack = 19; - let app_params = app_params_with_100_bits_security(DEFAULT_APP_L_SKIP + n_stack); - let agg_params = AggregationSystemParams::default(); - let sdk = make_verify_stark_path_sdk(app_params, agg_params)?; - let agg_vk = sdk.agg_vk().as_ref().clone(); - - let vs_elf = Elf::decode( - include_bytes!("../programs/examples/verify-stark.elf"), - MEM_SIZE as u32, - )?; - let vs_exe = sdk.convert_to_exe(vs_elf)?; - - let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&sdk)?; - assert!(fib_proof.deferral_merkle_proofs.is_some(),); - Sdk::verify_proof(agg_vk.clone(), fib_baseline.clone(), &fib_proof)?; - - let (vs_stdin, def_input) = make_verify_stark_inputs(&sdk, &fib_proof, fib_baseline)?; - let (vs_proof, vs_baseline) = sdk.prove(vs_exe.clone(), vs_stdin, &[def_input])?; - assert!(vs_proof.deferral_merkle_proofs.is_some(),); - Sdk::verify_proof(agg_vk.clone(), vs_baseline.clone(), &vs_proof)?; - - let (vs2_stdin, vs2_def_input) = make_verify_stark_inputs(&sdk, &vs_proof, vs_baseline)?; - let (vs2_proof, vs2_baseline) = sdk.prove(vs_exe, vs2_stdin, &[vs2_def_input])?; - assert!(vs2_proof.deferral_merkle_proofs.is_some(),); - Sdk::verify_proof(agg_vk, vs2_baseline, &vs2_proof)?; - - Ok(()) -} - -#[test] -fn test_deferrals_enabled_without_usage() -> Result<()> { - setup_tracing(); - let (fib_sdk, app_params, agg_params) = make_fib_sdk(); - let sdk = make_deferral_enabled_sdk(&fib_sdk, app_params, agg_params)?; - - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let app_exe = sdk.convert_to_exe(elf)?; - - let n = 1000u64; - let mut stdin = StdIn::default(); - stdin.write(&n); - - let mut evm_prover = sdk.evm_prover_without_halo2(app_exe)?; - let proof = evm_prover.prove_root(stdin, &[])?; - - // ---- Step 3: Verify the final result ---- - let vk = evm_prover.root_prover.0.get_vk(); - let engine = RootE::new(vk.inner.params.clone()); - engine.verify(&vk, &proof)?; - - Ok(()) -} - -#[test] -fn test_prove_mixed_vm_def_depth_mismatch() -> Result<()> { - setup_tracing(); - let (fib_sdk, app_params, agg_params) = make_fib_sdk(); - let (fib_proof, fib_baseline) = generate_fib_vm_stark_proof(&fib_sdk)?; - let (vs_sdk, vs_stdin, def_input) = - make_deferral_sdk(&fib_sdk, fib_proof, fib_baseline, app_params, agg_params)?; - - let vs_elf = Elf::decode( - include_bytes!("../programs/examples/verify-stark.elf"), - MEM_SIZE as u32, - )?; - let vs_exe = vs_sdk.convert_to_exe(vs_elf)?; - - // ---- Step 1: Generate base VM and deferral proofs ---- - let agg_prover = vs_sdk.agg_prover(); - let app_proof = vs_sdk.app_prover(vs_exe)?.prove(vs_stdin)?; - let (vm_proof, mut internal_layer_metadata) = agg_prover.prove_vm(app_proof)?; - - // We assume that the verify-stark program is small enough where only a single - // internal_recursive layer is needed to fully aggregate its proof. - assert_eq!(internal_layer_metadata.internal_recursive_layer, 1); - - let def_prover = vs_sdk.def_path_prover.unwrap(); - let def_hook_proofs = def_prover.deferral_prover.prove(&[def_input])?; - let (def_proof, mut def_internal_recursive_layer) = - def_prover.agg_prover.prove_def(def_hook_proofs)?; - assert_eq!(def_internal_recursive_layer, 1); - - // ---- Step 2: Generate mixed proof with wrapped VM proof ---- - let mut wrapped_vm_metadata = internal_layer_metadata.clone(); - let mut wrapped_vm_proof = vm_proof.clone(); - for _ in 0..2 { - wrapped_vm_proof = agg_prover.wrap_proof(wrapped_vm_proof, &mut wrapped_vm_metadata)?; - } - let wrapped_vm_mixed_proof = agg_prover.prove_mixed( - wrapped_vm_proof, - def_proof.clone(), - &mut wrapped_vm_metadata, - def_internal_recursive_layer, - )?; - - // ---- Step 3: Generate mixed proof with wrapped deferral proof ---- - let wrapped_def_proof = match def_proof { - DeferralProof::Present(mut p) => { - for _ in 0..2 { - p = agg_prover.wrap_def_inner(p, def_internal_recursive_layer)?; - def_internal_recursive_layer += 1; - } - DeferralProof::Present(p) - } - DeferralProof::Absent(_) => panic!("expected DeferralProof::Present"), - }; - let wrapped_def_mixed_proof = agg_prover.prove_mixed( - vm_proof, - wrapped_def_proof, - &mut internal_layer_metadata, - def_internal_recursive_layer, - )?; - - // ---- Step 4: Verify mixed proofs ---- - let vk = agg_prover.internal_recursive_prover.get_vk(); - let engine = E::new(vk.inner.params.clone()); - engine.verify(&vk, &wrapped_vm_mixed_proof.inner)?; - engine.verify(&vk, &wrapped_def_mixed_proof.inner)?; - - Ok(()) -} - -/// Cell-count profiling test for the static verifier circuit using a production root proof. -/// -/// Root verifier params match `pipeline_cell_count_profiling` in static-verifier crate. -/// The root proof is generated from a full SDK aggregation pipeline and cached to disk. -/// -/// Run with: -/// ```sh -/// OPENVM_CACHE_DIR=cache OPENVM_PROFILE_DIR=profile \ -/// cargo nextest run --cargo-profile=fast -p openvm-sdk --features cuda,cell-profiling \ -/// -- sdk_static_verifier_cell_profiling -/// ``` -#[cfg(feature = "cell-profiling")] -#[test] -fn sdk_static_verifier_cell_profiling() -> Result<()> { - use std::path::Path; - - use halo2_base::gates::circuit::{builder::BaseCircuitBuilder, CircuitBuilderStage}; - use openvm::platform::memory::MEM_SIZE; - use openvm_continuations::{CommitBytes, RootSC}; - use openvm_stark_backend::{ - codec::{Decode, Encode}, - proof::Proof, - }; - use openvm_stark_sdk::config::root_params_with_100_bits_security; - use openvm_static_verifier::{ - compute_dag_onion_commit, - field::baby_bear::{BabyBearChip, BabyBearExtChip}, - log_heights_per_air_from_proof, StaticVerifierCircuit, - }; - - use crate::{ - config::{AggregationSystemParams, DEFAULT_APP_L_SKIP}, - keygen::dummy::compute_root_proof_heights, - prover::{EvmProver, RootProver}, - Sdk, StdIn, - }; - - // Root verifier params matching pipeline_cell_count_profiling in static-verifier - let root_params = root_params_with_100_bits_security(); - let cache_dir = std::env::var("OPENVM_CACHE_DIR").unwrap_or_else(|_| "cache".to_string()); - std::fs::create_dir_all(&cache_dir)?; - - let proof_path = format!("{cache_dir}/sdk_root_proof.bin"); - let vk_path = format!("{cache_dir}/sdk_root_vk.bin"); - let commit_path = format!("{cache_dir}/sdk_onion_commit.bin"); - - let (root_vk, root_proof, onion_commit) = - if Path::new(&proof_path).exists() && Path::new(&vk_path).exists() { - eprintln!("Loading cached root proof from {cache_dir}/"); - let proof_bytes = std::fs::read(&proof_path)?; - let root_proof = Proof::::decode_from_bytes(&proof_bytes)?; - - let vk_bytes = std::fs::read(&vk_path)?; - let root_vk = bitcode::deserialize(&vk_bytes) - .map_err(|e| eyre::eyre!("failed to deserialize root VK: {e}"))?; - - let commit_bytes: [u8; 32] = std::fs::read(&commit_path)? - .try_into() - .map_err(|_| eyre::eyre!("invalid commit file"))?; - let onion_commit = CommitBytes::new(commit_bytes).into(); - - (root_vk, root_proof, onion_commit) - } else { - eprintln!("Generating root proof via SDK pipeline (this takes a while)..."); - let n_stack = 19; - let app_params = openvm_stark_sdk::config::app_params_with_100_bits_security( - DEFAULT_APP_L_SKIP + n_stack, - ); - let agg_params = AggregationSystemParams::default(); - - let elf = Elf::decode( - include_bytes!("../programs/examples/fibonacci.elf"), - MEM_SIZE as u32, - )?; - let sdk = Sdk::riscv64(app_params, agg_params); - let app_exe = sdk.convert_to_exe(elf)?; - - // Compute trace heights for root prover with profiling params - let system_config = sdk.app_config().app_vm_config.as_ref(); - let agg_prover = sdk.agg_prover(); - let (trace_heights, root_pk) = compute_root_proof_heights::( - sdk.app_vm_builder().clone(), - &sdk.app_pk().app_vm_pk, - agg_prover.clone(), - root_params.clone(), - None, - )?; - - let ir_vk = agg_prover.internal_recursive_prover.get_vk(); - let ir_pcs_data = agg_prover - .internal_recursive_prover - .get_self_vk_pcs_data() - .unwrap(); - let vk_commit: CommitBytes = ir_pcs_data.commitment.into(); - let onion_commit = compute_dag_onion_commit(&ir_vk); - - let memory_dimensions = system_config.memory_config.memory_dimensions(); - let num_user_pvs = system_config.num_public_values; - - let root_prover = Arc::new(RootProver::from_pk( - ir_vk, - vk_commit, - root_pk, - memory_dimensions, - num_user_pvs, - None, - Some(trace_heights), - )); - - let mut evm_prover = EvmProver::::new( - sdk.app_vm_builder().clone(), - &sdk.app_pk().app_vm_pk, - app_exe, - agg_prover, - None, - root_prover.clone(), - None, - )?; - - let n = 100u64; - let mut stdin = StdIn::default(); - stdin.write(&n); - - let root_proof = evm_prover.prove_root(stdin, &[])?; - let root_vk_arc = root_prover.0.get_vk(); - let root_vk = root_vk_arc.as_ref().clone(); - - // Verify the root proof - let engine = RootE::new(root_vk.inner.params.clone()); - engine.verify(&root_vk, &root_proof)?; - - // Cache to disk - eprintln!("Caching root proof to {cache_dir}/"); - std::fs::write(&proof_path, root_proof.encode_to_vec()?)?; - std::fs::write( - &vk_path, - bitcode::serialize(&root_vk) - .map_err(|e| eyre::eyre!("failed to serialize root VK: {e}"))?, - )?; - std::fs::write(&commit_path, CommitBytes::from(onion_commit).as_slice())?; - - (root_vk, root_proof, onion_commit) - }; - - // Run static verifier cell profiling - eprintln!("Running static verifier cell profiling..."); - let log_heights = log_heights_per_air_from_proof(&root_proof); - - let circuit = StaticVerifierCircuit::try_new(root_vk, onion_commit, &log_heights) - .expect("Failed to construct StaticVerifierCircuit"); - - let profile_dir = std::env::var("OPENVM_PROFILE_DIR").unwrap_or_else(|_| "profile".to_string()); - std::env::set_var("OPENVM_PROFILE_DIR", &profile_dir); - - let mut builder = BaseCircuitBuilder::from_stage(CircuitBuilderStage::Mock) - .use_k(22) - .use_lookup_bits(21) - .use_instance_columns(0); - let range = builder.range_chip(); - let ext_chip = BabyBearExtChip::new(BabyBearChip::new(Arc::new(range))); - let ctx = builder.main(0); - - let initial_cells = ctx.advice.len(); - circuit.populate_verify_stark_constraints(ctx, &ext_chip, &root_proof); - let final_cells = ctx.advice.len(); - eprintln!( - "Static verifier cell count: {} (delta: {})", - final_cells, - final_cells - initial_cells - ); - assert!( - final_cells > initial_cells, - "expected advice cells to increase" - ); - - Ok(()) -} diff --git a/patches/openvm-sdk/src/types.rs b/patches/openvm-sdk/src/types.rs deleted file mode 100644 index 7305a366..00000000 --- a/patches/openvm-sdk/src/types.rs +++ /dev/null @@ -1,502 +0,0 @@ -use std::sync::Arc; - -use derive_more::derive::From; -use eyre::Result; -use openvm::platform::memory::MEM_SIZE; -#[cfg(feature = "evm-prove")] -use openvm_circuit::arch::U16_CELL_SIZE; -use openvm_circuit::{ - arch::instructions::exe::VmExe, - system::memory::{dimensions::MemoryDimensions, merkle::public_values::UserPublicValuesProof}, -}; -use openvm_continuations::CommitBytes; -use openvm_stark_backend::{ - codec::{Decode, Encode}, - proof::Proof, -}; -use openvm_transpiler::elf::Elf; -use openvm_verify_stark_host::{ - deferral::DeferralMerkleProofs, pvs::VkCommit, vk::VerificationBaseline, VmStarkProof, -}; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; - -use crate::OPENVM_VERSION; - -#[derive(From)] -pub enum ExecutableFormat { - Elf(Elf), - VmExe(VmExe), - SharedVmExe(Arc>), -} - -impl<'a> From<&'a [u8]> for ExecutableFormat { - fn from(bytes: &'a [u8]) -> Self { - let elf = Elf::decode(bytes, MEM_SIZE.try_into().unwrap()).expect("Invalid ELF bytes"); - ExecutableFormat::Elf(elf) - } -} -impl From> for ExecutableFormat { - fn from(bytes: Vec) -> Self { - ExecutableFormat::from(&bytes[..]) - } -} - -/// Number of bytes in a Bn254. -#[allow(dead_code)] -pub(crate) const BN254_BYTES: usize = 32; -/// Number of Bn254 in `accumulator` field (KZG accumulator). -pub const NUM_BN254_ACCUMULATOR: usize = 12; -/// Number of Bn254 in `proof` field for a circuit with only 1 advice column. -#[cfg(feature = "evm-prove")] -#[allow(dead_code)] -pub(crate) const NUM_BN254_PROOF: usize = 43; - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct ProofData { - #[serde_as(as = "serde_with::hex::Hex")] - /// KZG accumulator. - pub accumulator: Vec, - #[serde_as(as = "serde_with::hex::Hex")] - /// Bn254 proof in little-endian bytes. The circuit only has 1 advice column, so the proof is - /// of length `NUM_BN254_PROOF * BN254_BYTES`. - pub proof: Vec, -} - -// =================== EVM types (evm-prove feature) =================== - -#[cfg(feature = "evm-prove")] -pub use openvm_static_verifier::wrapper::EvmVerifierByteCode; - -#[cfg(feature = "evm-prove")] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EvmHalo2Verifier { - pub halo2_verifier_code: String, - pub openvm_verifier_code: String, - pub openvm_verifier_interface: String, - pub artifact: EvmVerifierByteCode, -} - -/// Custom serde for CommitBytes as hex-encoded [u8; 32]. -pub mod hex_bytes32 { - use openvm_continuations::CommitBytes; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - pub fn serialize(val: &CommitBytes, s: S) -> Result { - format!("0x{}", hex::encode(val.as_slice())).serialize(s) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result { - let hex_str = String::deserialize(d)?; - let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str); - let bytes: [u8; 32] = hex::decode(hex_str) - .map_err(serde::de::Error::custom)? - .try_into() - .map_err(|_| serde::de::Error::custom("expected 32 bytes"))?; - Ok(CommitBytes::new(bytes)) - } -} - -/// Application execution commitment pair (big-endian 32-byte values). -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -pub struct AppExecutionCommit { - #[serde(with = "hex_bytes32")] - pub app_exe_commit: openvm_continuations::CommitBytes, - #[serde(with = "hex_bytes32")] - pub app_vm_commit: openvm_continuations::CommitBytes, -} - -#[cfg(feature = "evm-prove")] -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct EvmProof { - /// The openvm major and minor version v{}.{}. The proof format will not change on patch - /// versions. - pub version: String, - #[serde(flatten)] - /// Bn254 public value app commits. - pub app_commit: AppExecutionCommit, - #[serde_as(as = "serde_with::hex::Hex")] - /// User public values packed into bytes. - pub user_public_values: Vec, - /// Byte encoding of the `proof`. - pub proof_data: ProofData, -} - -#[cfg(feature = "evm-prove")] -#[derive(Debug, thiserror::Error)] -pub enum EvmProofConversionError { - #[error("Invalid length of instances: expected at least 3, got {0}")] - InvalidLengthInstances(usize), - #[error("Invalid length of user public values")] - InvalidUserPublicValuesLength, -} - -#[cfg(feature = "evm-prove")] -impl EvmProof { - #[cfg(feature = "evm-verify")] - /// Return bytes calldata to be passed to the verifier contract. - pub fn verifier_calldata(self) -> Vec { - use alloy_sol_types::SolCall; - - use crate::solidity::IOpenVmHalo2Verifier; - - let EvmProof { - user_public_values, - app_commit, - proof_data, - version: _, - } = self; - - let ProofData { accumulator, proof } = proof_data; - - let mut proof_data_bytes = accumulator; - proof_data_bytes.extend(proof); - - IOpenVmHalo2Verifier::verifyCall { - publicValues: user_public_values.into(), - proofData: proof_data_bytes.into(), - appExeCommit: (*app_commit.app_exe_commit.as_slice()).into(), - appVmCommit: (*app_commit.app_vm_commit.as_slice()).into(), - } - .abi_encode() - } - - #[cfg(feature = "evm-verify")] - pub fn fallback_calldata(&self) -> Vec { - let raw: openvm_static_verifier::keygen::RawEvmProof = self.clone().into(); - encode_raw_evm_proof_calldata(&raw) - } -} - -/// Encode a [`RawEvmProof`](openvm_static_verifier::keygen::RawEvmProof) as calldata for the -/// fallback (raw) verifier. -/// -/// Format: each instance as 32-byte big-endian, followed by raw proof bytes. -#[cfg(feature = "evm-verify")] -pub fn encode_raw_evm_proof_calldata( - proof: &openvm_static_verifier::keygen::RawEvmProof, -) -> Vec { - let mut calldata = Vec::new(); - for instance in &proof.instances { - // Fr::to_bytes() is little-endian; EVM expects big-endian - let mut bytes = instance.to_bytes(); - bytes.reverse(); - calldata.extend_from_slice(&bytes); - } - calldata.extend_from_slice(&proof.proof); - calldata -} - -/// Convert `RawEvmProof` → `EvmProof`. -/// -/// Instance layout (with KZG accumulator from wrapper circuit): -/// - `instances[0..12]`: KZG accumulator (12 Fr values) -/// - `instances[12]`: app_exe_commit (Fr) -/// - `instances[13]`: app_vm_commit (Fr) -/// - `instances[14..]`: user public values (each u16 limb as Fr) -#[cfg(feature = "evm-prove")] -impl From for EvmProof { - fn from(raw: openvm_static_verifier::keygen::RawEvmProof) -> Self { - use openvm_continuations::CommitBytes; - - let openvm_static_verifier::keygen::RawEvmProof { instances, proof } = raw; - assert!( - instances.len() > NUM_BN254_ACCUMULATOR + 2, - "RawEvmProof instances must have at least {} elements (accumulator + exe commit + vk commit)", - NUM_BN254_ACCUMULATOR + 2 - ); - - // instances[0..12] are the KZG accumulator - let accumulator = instances[0..NUM_BN254_ACCUMULATOR] - .iter() - .flat_map(|f| f.to_bytes()) - .collect::>(); - - // Reverse each 32-byte chunk for big-endian EVM format - let mut evm_accumulator = Vec::with_capacity(accumulator.len()); - accumulator - .chunks(BN254_BYTES) - .for_each(|chunk| evm_accumulator.extend(chunk.iter().rev().copied())); - - // instances[12] and [13] are Fr values encoding commits. - // Fr::to_bytes() returns 32 bytes in little-endian; CommitBytes expects big-endian. - let mut app_exe_bytes = instances[NUM_BN254_ACCUMULATOR].to_bytes(); - app_exe_bytes.reverse(); - let mut app_vm_bytes = instances[NUM_BN254_ACCUMULATOR + 1].to_bytes(); - app_vm_bytes.reverse(); - - let user_public_values = instances[NUM_BN254_ACCUMULATOR + 2..] - .iter() - .flat_map(|f| { - let bytes = f.to_bytes(); - debug_assert!( - bytes[U16_CELL_SIZE..].iter().all(|&byte| byte == 0), - "user public value limb must fit in u16" - ); - std::array::from_fn::<_, U16_CELL_SIZE, _>(|i| bytes[i]) - }) - .collect::>(); - - let app_commit = AppExecutionCommit { - app_exe_commit: CommitBytes::new(app_exe_bytes), - app_vm_commit: CommitBytes::new(app_vm_bytes), - }; - - Self { - version: format!("v{OPENVM_VERSION}"), - app_commit, - user_public_values, - proof_data: ProofData { - accumulator: evm_accumulator, - proof, - }, - } - } -} - -/// Convert `EvmProof` → `RawEvmProof`. -#[cfg(feature = "evm-prove")] -impl From for openvm_static_verifier::keygen::RawEvmProof { - fn from(evm_proof: EvmProof) -> Self { - use openvm_static_verifier::Fr; - - let EvmProof { - app_commit, - user_public_values, - proof_data, - version: _, - } = evm_proof; - - let ProofData { accumulator, proof } = proof_data; - - // Reverse each 32-byte chunk from big-endian (EVM) to little-endian (Fr) - let mut reversed_accumulator = Vec::with_capacity(accumulator.len()); - accumulator - .chunks(BN254_BYTES) - .for_each(|chunk| reversed_accumulator.extend(chunk.iter().rev().copied())); - - // CommitBytes is big-endian; Fr::from_bytes expects little-endian - let mut app_exe_bytes = *app_commit.app_exe_commit.as_slice(); - app_exe_bytes.reverse(); - let app_exe_fr = Fr::from_bytes(&app_exe_bytes).unwrap(); - - let mut app_vm_bytes = *app_commit.app_vm_commit.as_slice(); - app_vm_bytes.reverse(); - let app_vm_fr = Fr::from_bytes(&app_vm_bytes).unwrap(); - - assert!( - user_public_values.len().is_multiple_of(U16_CELL_SIZE), - "user public values length must be a multiple of {U16_CELL_SIZE}" - ); - let user_pvs_frs: Vec = user_public_values - .chunks_exact(U16_CELL_SIZE) - .map(|limb| { - let mut bytes = [0u8; 32]; - bytes[..U16_CELL_SIZE].copy_from_slice(limb); - Fr::from_bytes(&bytes).unwrap() - }) - .collect(); - - // Reconstruct instances: accumulator + commits + user PVs - let mut instances = Vec::new(); - for chunk in reversed_accumulator.chunks(BN254_BYTES) { - let c: [u8; 32] = chunk.try_into().unwrap(); - instances.push(Fr::from_bytes(&c).unwrap()); - } - instances.push(app_exe_fr); - instances.push(app_vm_fr); - instances.extend(user_pvs_frs); - - openvm_static_verifier::keygen::RawEvmProof { instances, proof } - } -} - -// =================== Non-EVM types =================== - -/// Struct purely for encoding and decoding of [VmStarkProof]. -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize, Encode, Decode)] -pub struct VersionedVmStarkProof { - /// The openvm major and minor version v{}.{}. The proof format will not change on patch - /// versions. - pub version: String, - #[serde_as(as = "serde_with::hex::Hex")] - pub proof: Vec, - #[serde_as(as = "serde_with::hex::Hex")] - pub user_pvs_proof: Vec, - #[serde(default)] - #[serde_as(as = "Option")] - pub deferral_merkle_proofs: Option>, -} - -impl VersionedVmStarkProof { - pub fn new(proof: VmStarkProof) -> Result { - Ok(Self { - version: format!("v{}", OPENVM_VERSION), - proof: proof.inner.encode_to_vec()?, - user_pvs_proof: { - let mut buf = Vec::new(); - proof.user_pvs_proof.encode::(&mut buf)?; - buf - }, - deferral_merkle_proofs: proof - .deferral_merkle_proofs - .map(|ref dmp| { - let mut buf = Vec::new(); - dmp.encode(&mut buf)?; - Ok::<_, std::io::Error>(buf) - }) - .transpose()?, - }) - } -} - -#[cfg(all(test, feature = "evm-prove"))] -mod tests { - use halo2_base::halo2_proofs::arithmetic::Field; - use openvm_static_verifier::{keygen::RawEvmProof, Fr}; - - use super::{EvmProof, NUM_BN254_ACCUMULATOR, U16_CELL_SIZE}; - - fn fr_from_u16(value: u16) -> Fr { - let mut bytes = [0u8; 32]; - bytes[..U16_CELL_SIZE].copy_from_slice(&value.to_le_bytes()); - Fr::from_bytes(&bytes).unwrap() - } - - #[test] - fn evm_proof_roundtrips_u16_public_values() { - let mut instances = vec![Fr::ZERO; NUM_BN254_ACCUMULATOR + 2]; - instances.extend([fr_from_u16(0x1234), fr_from_u16(0xabcd)]); - let raw = RawEvmProof { - instances, - proof: vec![1, 2, 3], - }; - - let proof = EvmProof::from(raw.clone()); - assert_eq!(proof.user_public_values, [0x34, 0x12, 0xcd, 0xab]); - - let roundtrip = RawEvmProof::from(proof); - assert_eq!(roundtrip.instances, raw.instances); - assert_eq!(roundtrip.proof, raw.proof); - } -} - -impl TryFrom for VmStarkProof { - type Error = std::io::Error; - fn try_from(proof: VersionedVmStarkProof) -> Result { - let VersionedVmStarkProof { - proof, - user_pvs_proof, - deferral_merkle_proofs, - .. - } = proof; - Ok(Self { - inner: Proof::::decode_from_bytes(&proof)?, - user_pvs_proof: UserPublicValuesProof::decode::( - &mut std::io::Cursor::new(&user_pvs_proof), - )?, - deferral_merkle_proofs: deferral_merkle_proofs - .map(|bytes| DeferralMerkleProofs::decode(&mut std::io::Cursor::new(&bytes))) - .transpose()?, - }) - } -} - -// =================== Verification baseline JSON types =================== - -/// Hex-formatted [`VkCommit`] for JSON serialization. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct VkCommitJson { - #[serde(with = "hex_bytes32")] - pub cached_commit: CommitBytes, - #[serde(with = "hex_bytes32")] - pub vk_pre_hash: CommitBytes, -} - -/// Hex-formatted [`VerificationBaseline`] for JSON serialization. -/// -/// Mirrors [`VerificationBaseline`] but serializes all commit fields as `0x`-prefixed hex strings, -/// consistent with [`AppExecutionCommit`]. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct VerificationBaselineJson { - #[serde(with = "hex_bytes32")] - pub app_exe_commit: CommitBytes, - pub memory_dimensions: MemoryDimensions, - pub num_user_pvs: usize, - pub app_vk_commit: VkCommitJson, - pub leaf_vk_commit: VkCommitJson, - pub internal_for_leaf_vk_commit: VkCommitJson, - pub internal_recursive_vk_commit: VkCommitJson, - #[serde(with = "option_hex_bytes32")] - pub expected_def_hook_commit: Option, -} - -impl From for VerificationBaselineJson { - fn from(b: VerificationBaseline) -> Self { - let vk = |d: VkCommit| VkCommitJson { - cached_commit: CommitBytes::from(d.cached_commit), - vk_pre_hash: CommitBytes::from(d.vk_pre_hash), - }; - Self { - app_exe_commit: CommitBytes::from(b.app_exe_commit), - memory_dimensions: b.memory_dimensions, - num_user_pvs: b.num_user_pvs, - app_vk_commit: vk(b.app_vk_commit), - leaf_vk_commit: vk(b.leaf_vk_commit), - internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit), - internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit), - expected_def_hook_commit: b.expected_def_hook_commit.map(CommitBytes::from), - } - } -} - -impl From for VerificationBaseline { - fn from(b: VerificationBaselineJson) -> Self { - use openvm_verify_stark_host::pvs::VkCommit; - let vk = |d: VkCommitJson| VkCommit { - cached_commit: d.cached_commit.into(), - vk_pre_hash: d.vk_pre_hash.into(), - }; - Self { - app_exe_commit: b.app_exe_commit.into(), - memory_dimensions: b.memory_dimensions, - num_user_pvs: b.num_user_pvs, - app_vk_commit: vk(b.app_vk_commit), - leaf_vk_commit: vk(b.leaf_vk_commit), - internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit), - internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit), - expected_def_hook_commit: b.expected_def_hook_commit.map(|c| c.into()), - } - } -} - -/// Custom serde for `Option` as hex-encoded `[u8; 32]`. -pub mod option_hex_bytes32 { - use openvm_continuations::CommitBytes; - use serde::{Deserialize, Deserializer, Serializer}; - - pub fn serialize(val: &Option, s: S) -> Result { - match val { - Some(v) => super::hex_bytes32::serialize(v, s), - None => s.serialize_none(), - } - } - - pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { - let opt: Option = Option::deserialize(d)?; - match opt { - Some(hex_str) => { - let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str); - let bytes: [u8; 32] = hex::decode(hex_str) - .map_err(serde::de::Error::custom)? - .try_into() - .map_err(|_| serde::de::Error::custom("expected 32 bytes"))?; - Ok(Some(CommitBytes::new(bytes))) - } - None => Ok(None), - } - } -} diff --git a/patches/openvm-sdk/src/util.rs b/patches/openvm-sdk/src/util.rs deleted file mode 100644 index 5d260941..00000000 --- a/patches/openvm-sdk/src/util.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::cmp::Ordering; - -use openvm_circuit::arch::SystemConfig; - -pub fn check_max_constraint_degrees(config: &SystemConfig, max_constraint_degree: usize) { - match config.max_constraint_degree.cmp(&max_constraint_degree) { - Ordering::Greater => { - tracing::warn!( - "config.max_constraint_degree ({}) > vk max_constraint_degree() ({})", - config.max_constraint_degree, - max_constraint_degree - ); - } - Ordering::Less => { - tracing::info!( - "config.max_constraint_degree ({}) < vk max_constraint_degree() ({})", - config.max_constraint_degree, - max_constraint_degree - ); - } - Ordering::Equal => {} - } -} diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin deleted file mode 100644 index d5217e27a93575a636b1a01751f6994da9f7c441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19459 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 aSchAYW2=_`{C)1wj|TK;!8uprV*d~2AXG2_ diff --git a/releases/dev/verifier/verifier.sol b/releases/dev/verifier/verifier.sol deleted file mode 100644 index cb68597d..00000000 --- a/releases/dev/verifier/verifier.sol +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.19; - -import { Halo2Verifier } from "./Halo2Verifier.sol"; -import { IOpenVmHalo2Verifier } from "./interfaces/IOpenVmHalo2Verifier.sol"; - -type MemoryPointer is uint256; - -/// @notice This contract provides a thin wrapper around the Halo2 verifier -/// outputted by `snark-verifier`, exposing a more user-friendly interface. -contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { - /// @dev Invalid public values length - error InvalidPublicValuesLength(uint256 expected, uint256 actual); - - /// @dev Invalid proof data length - error InvalidProofDataLength(uint256 expected, uint256 actual); - - /// @dev Proof verification failed - error ProofVerificationFailed(); - - /// @dev The length of the proof data, in bytes. - uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32; - - /// @dev The number of public value limbs exposed by the Halo2 circuit. - /// This value is set by OpenVM and is guaranteed to be no larger than 8192. - uint256 private constant PUBLIC_VALUES_LENGTH = 32; - - /// @dev The byte width of each public value limb (1 for rv32, 2 for rv64). - uint256 private constant PUBLIC_VALUES_LIMB_SIZE = 2; - - /// @dev The total byte length of the public values payload. - uint256 private constant PUBLIC_VALUES_BYTE_LENGTH = PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE; - - /// @dev The length of the full proof, in bytes - uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32; - - /// @dev The version of OpenVM that generated this verifier. - string public constant OPENVM_VERSION = "2.0"; - - /// @notice A wrapper that constructs the proof into the right format for - /// use with the `snark-verifier` verification. - /// - /// @dev The verifier expected proof format is: - /// proof[..12 * 32]: KZG accumulator - /// proof[12 * 32..13 * 32]: app exe commit - /// proof[13 * 32..14 * 32]: app vm commit - /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] - /// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix - /// - /// @param publicValues The PVs revealed by the OpenVM guest program. Each - /// public-value limb occupies PUBLIC_VALUES_LIMB_SIZE bytes in little-endian. - /// @param proofData All components of the proof except the public values and - /// app exe and vm commits. The expected format is: - /// `abi.encodePacked(kzgAccumulator, proofSuffix)` - /// @param appExeCommit The commitment to the OpenVM application executable whose execution - /// is being verified. - /// @param appVmCommit The commitment to the VM configuration. - function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { - if (publicValues.length != PUBLIC_VALUES_BYTE_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_BYTE_LENGTH, publicValues.length); - if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length); - - // We will format the public values and construct the full proof payload - // below. - - MemoryPointer proofPtr = _constructProof(publicValues, proofData, appExeCommit, appVmCommit); - - uint256 fullProofLength = FULL_PROOF_LENGTH; - - /// @solidity memory-safe-assembly - assembly { - // Self-call using the proof as calldata - if iszero(staticcall(gas(), address(), proofPtr, fullProofLength, 0, 0)) { - mstore(0x00, 0xd611c318) // ProofVerificationFailed() - revert(0x1c, 0x04) - } - } - } - - /// @dev The assembly code should perform the same function as the following - /// solidity code: - // - /// ```solidity - /// bytes memory proof = - /// abi.encodePacked(proofData[0:0x180], appExeCommit, appVmCommit, publicValuesPayload, proofData[0x180:]); - /// ``` - // - /// where `publicValuesPayload` is a memory payload with each byte in - /// `publicValues` separated into its own `bytes32` word. - /// - /// This function does not clean the memory it allocates. Since it is the - /// only memory write that occurs in the call frame, we know that - /// the memory region cannot have been dirtied. - /// - /// @return proofPtr Memory pointer to the beginning of the constructed - /// proof. This pointer does not follow `bytes memory` semantics. - function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) - internal - pure - returns (MemoryPointer proofPtr) - { - uint256 fullProofLength = FULL_PROOF_LENGTH; - - // The expected proof format using hex offsets: - // - // proof[..0x180]: KZG accumulator - // proof[0x180..0x1a0]: app exe commit - // proof[0x1a0..0x1c0]: app vm commit - // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValue limbs[0..PUBLIC_VALUES_LENGTH] - // proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix - - /// @solidity memory-safe-assembly - assembly { - proofPtr := mload(0x40) - // Allocate the memory as a safety measure. - mstore(0x40, add(proofPtr, fullProofLength)) - - // Copy the KZG accumulator (length 0x180) into the beginning of - // the memory buffer - calldatacopy(proofPtr, proofData.offset, 0x180) - - // Copy the App Exe Commit and App Vm Commit into the memory buffer - mstore(add(proofPtr, 0x180), appExeCommit) - mstore(add(proofPtr, 0x1a0), appVmCommit) - - // Copy the Proof Suffix (length 43 * 32 = 0x560) into the - // end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in - // between for the publicValuesPayload. - // - // Begin copying from the end of the KZG accumulator in the - // calldata buffer (0x180) - let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) - calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) - - // Copy each public-value limb into the low bytes of the corresponding - // Fr slot. user_public_values stores limbs in little-endian, but each - // 32-byte word is interpreted by the EVM as big-endian, so we reverse - // the limb bytes as we copy them to the end of the word. - for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - let wordPtr := add(proofPtr, add(0x1c0, shl(5, i))) - // Clear the full word first; only the low bytes are overwritten. - mstore(wordPtr, 0) - for { let j := 0 } iszero(eq(j, PUBLIC_VALUES_LIMB_SIZE)) { j := add(j, 1) } { - // publicValues[i*LIMB_SIZE + j] is copied to the j-th byte - // from the end of the word, i.e. wordPtr + (0x1f - j). - calldatacopy( - add(wordPtr, sub(0x1f, j)), - add(publicValues.offset, add(mul(i, PUBLIC_VALUES_LIMB_SIZE), j)), - 0x01 - ) - } - } - } - } -} From 741b0835c23227ca875a4ab3607affd562a9e779 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 30 Jun 2026 08:59:16 +0800 Subject: [PATCH 19/19] mid --- crates/build-guest/src/post_process.rs | 154 +++++++++++++++++++++ crates/integration/src/bin/prover-split.rs | 117 ++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 crates/build-guest/src/post_process.rs create mode 100644 crates/integration/src/bin/prover-split.rs diff --git a/crates/build-guest/src/post_process.rs b/crates/build-guest/src/post_process.rs new file mode 100644 index 00000000..d943432d --- /dev/null +++ b/crates/build-guest/src/post_process.rs @@ -0,0 +1,154 @@ +//! Application-level post-processing for OpenVM-generated EVM verifier Solidity. +//! +//! OpenVM's upstream `OpenVmHalo2Verifier` template is written for rv32, where +//! each public-value cell is a single byte. On rv64 each cell is a 2-byte +//! little-endian u16 limb, so the wrapper must: +//! +//! 1. Receive `publicValues` as a byte array whose length is +//! `PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE`. +//! 2. Reverse each little-endian limb into the high bytes of the corresponding +//! 32-byte Fr word (EVM interprets words as big-endian). +//! +//! This module transforms the upstream-generated wrapper into the rv64 format +//! without patching `openvm-sdk` itself. + +use eyre::Result; + +/// Post-process an rv32-oriented `OpenVmHalo2Verifier.sol` so that it supports +/// rv64 public-value limbs. +/// +/// Returns the transformed Solidity source. The input must still contain the +/// upstream public-values copying logic. +pub fn post_process_openvm_verifier_for_rv64(sol_code: &str) -> Result { + // Extract the number of public-value limbs from the generated constant. + let pvs_length = extract_public_values_length(sol_code)?; + + let mut out = sol_code.to_string(); + + // 1. Update the PUBLIC_VALUES_LENGTH comment and add limb-size constants. + out = out.replace( + "/// @dev The length of the public values, in bytes. This value is set by\n /// OpenVM and is guaranteed to be no larger than 8192.", + "/// @dev The number of public value limbs exposed by the Halo2 circuit.\n /// This value is set by OpenVM and is guaranteed to be no larger than 8192.", + ); + + let pvs_const = format!( + "uint256 private constant PUBLIC_VALUES_LENGTH = {pvs_length};" + ); + let pvs_const_replacement = format!( + "{pvs_const}\n\n /// @dev The byte width of each public value limb (1 for rv32, 2 for rv64).\n uint256 private constant PUBLIC_VALUES_LIMB_SIZE = 2;\n\n /// @dev The total byte length of the public values payload.\n uint256 private constant PUBLIC_VALUES_BYTE_LENGTH = PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE;" + ); + out = out.replace(&pvs_const, &pvs_const_replacement); + + // 2. Fix the length check in verify(). + out = out.replace( + "if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length);", + "if (publicValues.length != PUBLIC_VALUES_BYTE_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_BYTE_LENGTH, publicValues.length);", + ); + + // 3. Fix the doc comment in _constructProof that refers to bytes. + out = out.replace( + "/// proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH]", + "/// proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValue limbs[0..PUBLIC_VALUES_LENGTH]", + ); + out = out.replace( + "/// @param publicValues The PVs revealed by the OpenVM guest program.", + "/// @param publicValues The PVs revealed by the OpenVM guest program. Each\n /// public-value limb occupies PUBLIC_VALUES_LIMB_SIZE bytes in little-endian.", + ); + + // 4. Replace the public-values copying loop. + // Upstream copies one byte per limb into offset 0x1f. We need to copy a + // little-endian 2-byte limb into offsets 0x1e (high) and 0x1f (low). + let old_loop = r#"// Copy each byte of the public values into the proof. It copies the + // most significant bytes of public values first. + let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) + }"#; + + let new_loop = r#"// Copy each public-value limb into the low bytes of the corresponding + // Fr slot. user_public_values stores limbs in little-endian, but each + // 32-byte word is interpreted by the EVM as big-endian, so we reverse + // the limb bytes as we copy them to the end of the word. + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + let wordPtr := add(proofPtr, add(0x1c0, shl(5, i))) + // Clear the full word first; only the low bytes are overwritten. + mstore(wordPtr, 0) + for { let j := 0 } iszero(eq(j, PUBLIC_VALUES_LIMB_SIZE)) { j := add(j, 1) } { + // publicValues[i*LIMB_SIZE + j] is copied to the j-th byte + // from the end of the word, i.e. wordPtr + (0x1f - j). + calldatacopy( + add(wordPtr, sub(0x1f, j)), + add(publicValues.offset, add(mul(i, PUBLIC_VALUES_LIMB_SIZE), j)), + 0x01 + ) + } + }"#; + + if !out.contains(old_loop) { + return Err(eyre::eyre!( + "upstream public-values loop not found; cannot post-process verifier.sol" + )); + } + out = out.replace(old_loop, new_loop); + + Ok(out) +} + +fn extract_public_values_length(sol_code: &str) -> Result { + let re = regex::Regex::new( + r"uint256\s+private\s+constant\s+PUBLIC_VALUES_LENGTH\s*=\s*(\d+)\s*;", + ) + .unwrap(); + let caps = re + .captures(sol_code) + .ok_or_else(|| eyre::eyre!("PUBLIC_VALUES_LENGTH constant not found in verifier.sol"))?; + let value: usize = caps[1] + .parse() + .map_err(|e| eyre::eyre!("failed to parse PUBLIC_VALUES_LENGTH: {e}"))?; + Ok(value) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_post_process_rv64() { + let upstream = r#"// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +contract OpenVmHalo2Verifier { + /// @dev The length of the public values, in bytes. This value is set by + /// OpenVM and is guaranteed to be no larger than 8192. + uint256 private constant PUBLIC_VALUES_LENGTH = 32; + + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { + if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length); + } + + function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + internal + pure + returns (MemoryPointer proofPtr) + { + /// @solidity memory-safe-assembly + assembly { + // Copy each byte of the public values into the proof. It copies the + // most significant bytes of public values first. + let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) + } + } + } +} +"#; + + let processed = post_process_openvm_verifier_for_rv64(upstream).unwrap(); + assert!(processed.contains("PUBLIC_VALUES_LIMB_SIZE = 2")); + assert!(processed.contains("PUBLIC_VALUES_BYTE_LENGTH = PUBLIC_VALUES_LENGTH * PUBLIC_VALUES_LIMB_SIZE")); + assert!(processed.contains("publicValues.length != PUBLIC_VALUES_BYTE_LENGTH")); + assert!(processed.contains("add(wordPtr, sub(0x1f, j))")); + assert!(!processed.contains("let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f)")); + } +} diff --git a/crates/integration/src/bin/prover-split.rs b/crates/integration/src/bin/prover-split.rs new file mode 100644 index 00000000..7a031ec0 --- /dev/null +++ b/crates/integration/src/bin/prover-split.rs @@ -0,0 +1,117 @@ +//! Split-process helper for STARK/SNARK proving. +//! +//! Running OpenVM STARK proving and Halo2 SNARK proving in the same process on a +//! 24 GB GPU exhausts VRAM because the parent process already ran chunk/batch +//! STARK proving before the bundle EVM proof. This binary is spawned to generate +//! the bundle EVM proof in a fresh process with a clean CUDA context. + +use std::path::PathBuf; + +use clap::Parser; +use eyre::Result; +use bincode_v1; +use openvm_circuit::arch::deferral::DeferralState; +use openvm_sdk::DeferralInput; +use scroll_zkvm_prover::{Prover, ProverConfig}; +use scroll_zkvm_types::task::ProvingTask as UniversalProvingTask; +use tracing_subscriber::EnvFilter; + +use scroll_zkvm_integration::TaskProver; + +#[derive(Parser)] +struct Cli { + #[command(subcommand)] + cmd: Cmd, +} + +#[derive(Parser)] +enum Cmd { + /// Generate an EVM proof for the final circuit in a fresh process. + /// The binary loads the full prover chain (chunk -> batch -> bundle) and + /// enables deferral before running STARK + SNARK proving. + Evm { + /// Directory containing the released assets (`chunk/`, `batch/`, `bundle/`, `verifier/`). + #[arg(long)] + asset_base_dir: PathBuf, + /// Target circuit name ("bundle" or "batch"). + #[arg(long)] + circuit: String, + /// Path to the serialized [`UniversalProvingTask`]. + #[arg(long)] + task: PathBuf, + /// Path to the serialized `Vec`. + #[arg(long)] + def_inputs: PathBuf, + /// Path to the serialized `Vec`. + #[arg(long)] + def_states: PathBuf, + /// Path to write the JSON-encoded [`ProofEnum`]. + #[arg(long)] + output: PathBuf, + }, +} + +fn load_prover(asset_base_dir: &std::path::Path, name: &str) -> Result { + let config = ProverConfig { + path_app_exe: asset_base_dir.join(name).join("app.vmexe"), + path_app_config: asset_base_dir.join(name).join("openvm.toml"), + ..Default::default() + }; + Ok(Prover::setup(config, Some(name))?) +} + +/// Build the prover chain for the target circuit and enable deferral from leaf to root. +/// For "bundle" the chain is chunk -> batch -> bundle. +/// For "batch" the chain is chunk -> batch. +fn build_prover_chain(asset_base_dir: &std::path::Path, circuit: &str) -> Result { + match circuit { + "bundle" => { + let chunk_prover = load_prover(asset_base_dir, "chunk")?; + let mut batch_prover = load_prover(asset_base_dir, "batch")?; + batch_prover.enable_deferral(&chunk_prover)?; + let mut bundle_prover = load_prover(asset_base_dir, "bundle")?; + bundle_prover.enable_deferral(&batch_prover)?; + Ok(bundle_prover) + } + "batch" => { + let chunk_prover = load_prover(asset_base_dir, "chunk")?; + let mut batch_prover = load_prover(asset_base_dir, "batch")?; + batch_prover.enable_deferral(&chunk_prover)?; + Ok(batch_prover) + } + other => eyre::bail!("unsupported circuit for split proving: {other}"), + } +} + +fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let cli = Cli::parse(); + + match cli.cmd { + Cmd::Evm { + asset_base_dir, + circuit, + task, + def_inputs, + def_states, + output, + } => { + let mut prover = build_prover_chain(&asset_base_dir, &circuit)?; + + let task: UniversalProvingTask = bincode_v1::deserialize(&std::fs::read(&task)?)?; + let def_inputs: Vec = + bincode_v1::deserialize(&std::fs::read(&def_inputs)?)?; + let def_states: Vec = + bincode_v1::deserialize(&std::fs::read(&def_states)?)?; + + let proof = prover.prove_task_with_deferral(&task, true, &def_inputs, &def_states)?; + let json = serde_json::to_string(&proof)?; + std::fs::write(&output, json)?; + } + } + + Ok(()) +}